Почему вместо метода "новый" используется метод Create?

В чем преимущества и когда целесообразно использовать статический конструктор?

public class MyClass
{
    protected MyClass()
    {
    }

    public static MyClass Create()
    {
        return new MyClass();
    }
}

а затем создав экземпляр класса с помощью

MyClass myClass = MyClass.Create();

в отличие от простого публичного конструктора и создания объектов с использованием

MyClass myClass = new MyClass();

Я вижу, что первый подход полезен, если метод Create возвращает экземпляр интерфейса, который реализует класс... он заставил бы вызывающих объектов создавать экземпляры интерфейса, а не конкретного типа.

Ответ 1

Это шаблон factory, и его часто можно использовать для создания подкласса, но разрешить параметрам статический метод определить, какой из них.

Он также может использоваться, если новый объект не всегда требуется, например, в реализации объединения.

Он также может использоваться, если все экземпляры объекта необходимо кэшировать или иным образом регистрировать при создании. Это гарантирует, что клиент не забудет это сделать.

И, конечно же, это неотъемлемая часть шаблона Singleton.

Ответ 2

Это не одноэлемент... Create будет возвращать один и тот же экземпляр каждый раз, если бы это было.

Это шаблон factory. Обычно я делаю это с интерфейсами не классов, поэтому я должен растягиваться здесь, но надуманный пример:

public static MyClass Create()
{
    if(OS == Windows)
        return new MyDerivedClassForWindows();
    else if(OS == Linux)
        return new MyDerivedClassForLinux();
    etc....
}

Ответ 3

Конкретный пример, который вы опубликовали, не имеет никакого преимущества перед использованием обычного конструктора. Однако существуют два общих шаблона, которые используют способ, подобный этому, для создания объекта:

Шаблон Singleton

Шаблон singleton можно использовать, если вы хотите предотвратить создание нескольких экземпляров объекта, но все же хотите использовать объектно-ориентированные аспекты класса (например, поля, свойства, безпараметрические методы). Пример:

public class MySingletonClass
{
    private MySingletonClass currentInstance = null;

    public MySingletonClass CreateInstance()
    {
         if (currentInstance == null)
         {
              currentInstance = new MySingletonClass();
         }
         else
         {
              return currentInstance;
         }
    }
}

Factory Шаблон

Шаблон factory - прекрасная возможность отвлечь создание конкретных классов; например, предположим, что у вас есть некоторый XML, и в зависимости от того, какой из node (NodeA, NodeB или NodeC) вы видите в XML, у вас есть другой класс, который будет обрабатывать его. Пример:

public class MyXmlProcessorFactory
{
    public static IMyXmlProcessor GetMyXmlProcessor(XmlDocument document)
    {
         XmlNode rootNode = document.DocumentElement;

         if (rootNode.SelectSingleNode("NodeA") != null)
         {
              return new NodeAMyXmlProcessor();
         }
         else if (rootNode.SelectSingleNode("NodeB") != null)
         {
              return new NodeBMyXmlProcessor();
         }
         else if (rootNode.SelectSingleNode("NodeC") != null)
         {
              return new NodeCMyXmlProcessor();
         }
         else
         {
              return new DefaultMyXmlProcessor();
         }
    }
}

Ответ 4

Другая причина, продемонстрированная статическим методом Guid.NewGuid(), заключается в том, что тип является структурой. В этом случае CLR требует, чтобы конструктор без параметров без параметров создавал новый экземпляр со всеми полями, инициализированными значениями по умолчанию. В случае с Guid это означает:

Guid g = new Guid();

будет Guid.Empty. Очевидно, что вы хотите создать новый Guid, который рандомизирован, поэтому метод Guid.NewGuid() - это способ сделать это.

Ответ 5

Вы правы. Это не шаблон Singleton. Это шаблон Factory.

Использование Create() вместо нового дает позволяет давать осмысленные имена методам, тем самым давая пользователю больше ясности

Возьмите это, например:

public class User
{
    public int id;
    public string userName;
    public string password;
    public string role;

    private User() { }

    public static User CreateByCredentials(string uid, string pwd)
    {
        User user = new User();
        user.userName = uid;
        user.password = pwd;
        return user;
    }

    public static User CreateById(int id)
    {
        User user = new User();
        user.id = id;
        return user;
    }

}

Есть два преимущества для этого подхода:

  • Мы можем вернуть нулевой объект, который невозможно сделать с помощью конструктора (это может быть или не быть полезным во всех случаях.)
  • Если существует много разных способов создания объекта, это дает вам возможность предоставить более значимые имена функций. В примере у вас есть User.CreateByCredentials(имя пользователя строки, строковый пароль) и User.CreateById(int id). Вы можете выполнить ту же функциональность с перегрузкой конструктора, но редко с той же ясностью.

Ответ 6

Может быть полезно в случаях, когда несколько экземпляров класса используют один и тот же блок инициализированных данных - это шаблон OOP factory.

Примером может служить класс, который подключается к базе данных - требуется только одно соединение и может использоваться всеми экземплярами класса.

http://en.wikipedia.org/wiki/Factory_pattern

Billy3

Ответ 7

Более формально это обычно называют Заменить конструктор с помощью метода Factory

Вы хотите сделать больше, чем простое построение при создании объекта.

то есть. используя метод Factory, вы можете быть более явным и иметь больше вариантов создания, доступных для кода над простым конструктором.

Я бы рекомендовал книгу Рефакторинг: Улучшение дизайна существующего кода (Fowler)

Ответ 8

Этот шаблон обычно используется в Singleton pattern. Это полезно, когда у вас есть класс или фасад для класса, который должен быть создан только один раз во время жизни программы, как правило, из-за ресурсов, которые будет использовать этот объект.

Как в С#

Ответ 9

Существуют различные причины, по которым вы можете это сделать, например, чтобы всегда возвращать экземпляр из пула фиксированных объектов (включая объект Singleton) или, как вы говорите, возвращать экземпляры интерфейса.

Но если у вас нет ясной причины сделать это, не делайте этого.

Ответ 10

Этот подход используется только для синглтонов, иначе этот подход неортодоксален. Не используйте, пока не поймете, что он пытается сделать.

Ответ 11

Это хороший способ заставить MyClass быть окончательным, если вы используете частный конструктор. Таким образом, подклассы не могут быть созданы, потому что их конструктор не может получить доступ к супер-конструктору.

Другим преимуществом является то, что у вас есть один параметр для конструктора. Затем вы можете назвать создание с эмуляцией именованных аргументов:

public static MyClass createWithDays(int days) {
...
}

Теперь сравните new MyClass(5) с MyClass.createWithDays(5)

Ответ 12

Кроме того, когда один синглтон, имеющий "статический метод factory", такой как MyClass.Create, может быть полезен, если человек, который реализует MyClass.Create, может захотеть вернуть подкласс MyClass... например во время тестирования он может вернуть экземпляр подкласса MyClassWithExtraTestingFunctionality... или, в зависимости от параметра конфигурации, экземпляр подкласса MyClassBeingRemotedOverTheNetwork...

Ответ 13

Многие из других ответов охватывают конкретные случаи, когда эта идея может быть полезна. Идея создания инкапсулирующего экземпляра используется во многих инфраструктурах IoC, таких как Spring, Castle и т.д. Идея состоит в том, что путем централизации создания экземпляра вы можете настроить конфигурацию своего приложения для использования другого набора объектов. Общим примером является ведение журнала. Изменив конфигурацию, вы можете сообщить своему журналу factory, чтобы создать различные экземпляры ваших классов ведения журнала в соответствии с ситуацией.

При применении эта идея может привести к очень слабо связанным системам, которые могут быть легко изменены после развертывания или даже во время выполнения. Однако сложность возрастает по мере того, как у вас есть другой уровень косвенности.

Ответ 14

Статический конструктор также является хорошим способом дать более явные имена вашему конструктору. Это также может быть полезно для параметра по умолчанию

ex: Myclass.create(); вместо нового Myclass (defaultParam1, defaultParam2...)

Джошуа Блох рассказывает об этом в эффективной Java (пункт 1)

Ответ 15

Это также обычно используется, когда вы хотите, чтобы фреймворк, класс или какая-либо другая конфигурация определяли WHERE, что объект действительно будет создан. Когда вы используете подход нового конструктора, он создается локально. Если вы используете этот подход, его можно потенциально создать удаленно с помощью служебного вызова и вернуть его и т.д. Это подход, сделанный Роки Лоткой в ​​CSLA framework.

Ответ 16

Также это может быть использовано в случае ленивой загрузки. Где вы хотите, чтобы объект был по какой-то причине, но не хотите делать все тяжелые операции, связанные с реальным конструктором, если это не требуется. Таким образом, вы создаете отдельный метод Create и называете его, когда будете готовы к тяжелой работе.

Также @Rashmi Pandit писал (а):

   public static User CreateByCredentials(string uid, string pwd)
    {
       ....
    }

    public static User CreateById(int id)
    {
    ...
    }

В ответ вы не можете просто использовать перегруженные конструкторы с разными сигнатурами методов вместо создания двух разных методов создания?

Ответ 17

Обратите внимание, что вы можете использовать инициализацию конструктора только при использовании подхода конструктора.

    public void Example()
    {
        var person = new Person
                         {
                             GivenName = "John",
                             FamilyName = "Smith",
                             Address = new Address
                                           {
                                               Street = "Wallace",
                                               Number = 12
                                           },
                             PhoneNumbers = new List<PhoneNumber>
                                                {
                                                    new PhoneNumber
                                                        {
                                                            Number = 1234234,
                                                            AreaCode = 02
                                                        },
                                                    new PhoneNumber
                                                        {
                                                            Number = 1234234, AreaCode = 02
                                                        }
                                                }
                         };
    }

    internal class PhoneNumber
    {
        public int AreaCode { get; set; }

        public int Number { get; set; }
    }

    internal class Address
    {
        public int Number { get; set; }

        public string Street { get; set; }
    }

    internal class Person
    {
        public Address Address { get; set; }

        public string GivenName { get; set; }

        public string FamilyName { get; set; }

        public List<PhoneNumber> PhoneNumbers { get; set; }
    }
}