Зачем использовать метод Create вместо использования «new»? - PullRequest
11 голосов
/ 18 мая 2009

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

public class MyClass
{
    protected MyClass()
    {
    }

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

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

MyClass myClass = MyClass.Create();

, а не просто открытый конструктор и создание объектов с использованием

MyClass myClass = new MyClass();

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

Ответы [ 17 ]

15 голосов
/ 18 мая 2009

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

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

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

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

8 голосов
/ 18 мая 2009

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

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

public static MyClass Create()
{
    if(OS == Windows)
        return new MyDerivedClassForWindows();
    else if(OS == Linux)
        return new MyDerivedClassForLinux();
    etc....
}
4 голосов
/ 18 мая 2009

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

Шаблон синглтона

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

public class MySingletonClass
{
    private MySingletonClass currentInstance = null;

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

Заводская модель

Фабричный шаблон - прекрасная возможность абстрагироваться от создания конкретных классов; например, давайте на мгновение предположим, что у вас есть некоторый XML, и в зависимости от того, какой узел (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();
         }
    }
}
3 голосов
/ 18 мая 2009

Вы правы. Это не модель Синглтона. Это фабричный образец.

Использование метода 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;
    }

}

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

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

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

Guid g = новый Guid ();

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

2 голосов
/ 18 мая 2009

Более формально, это обычно упоминается как Замените конструктор фабричным методом

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

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

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

2 голосов
/ 18 мая 2009

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

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

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

Billy3

1 голос
/ 18 мая 2009

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

Например: Myclass.create (); целое число нового Myclass (defaultParam1, defaultParam2 ...)

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

1 голос
/ 18 мая 2009

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

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

1 голос
/ 18 мая 2009

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...