Factory vs конструкторы экземпляров

Я не могу придумать никаких причин, почему один лучше другого. Сравните эти две реализации:

public class MyClass
{
    public MyClass(string fileName)
    {
        // some code...
    }
}

в отличие от:

public class MyClass
{
    private MyClass(){}

    public static MyClass Create(string fileName)
    {
       // some code...
    }
}

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

Какова причина этого стиля?

Ответ 1

Примечание. То, что у вас есть, не является статическим конструктором, это статическая функция, которая создает экземпляр вместо вызова конструктора экземпляра. Статический конструктор совсем другой.

Шаблон factory является классическим примером использования функции (статической или нет) для создания экземпляра типа, а не непосредственного использования конструктора. Обратите внимание, что фактический конструктор экземпляра будет вызван независимо от того, что, но статическая функция предоставляет слой косвенности, который позволяет ему возвращать экземпляр любого типа, который либо является, либо наследуется от типа возврата, а не только экземпляры, которые являются возвратом тип.

Например:

public abstract class BaseClass
{
    public static BaseClass Create(int parameter)
    {
        if (parameter == 1)
        {
            return new Class1();
        }
        else
        {
            return new Class2();
        }
    }
}

internal class Class1 : BaseClass
{
    //code here ...
}

internal class Class2 : BaseClass
{
    //code here ...
}

Это позволяет скрыть Class1 и Class2 от внешних сборок, в то же время позволяя потребителю иметь дело с чем-то специализированным.

Ответ 2

Я изучал этот момент и наткнулся на этот вопрос, но не чувствовал, что на него полностью ответили. Тем не менее, я нашел эту удобную статью - Обновление правил проектирования: фабрики и конструкторы - Кржиштоф Квалина (главный архитектор на .NET Framework), Стоит прочитать всю статью, но вот краткий обзор основных моментов:

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

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

Выполнять операции Factory как методы, а не свойства.

Вернуть экземпляры как возвращаемые значения метода, а не как параметры out.

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

Рассмотрим имена методов Factory, объединив "Создать" и имя создаваемого типа.

Рассмотрим имена типов Factory путем объединения имени типа, являющегося и

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

Используйте Factory для операций стиля преобразования.

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

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

Рассмотрим использование конструктора вместо Factory. Только после этого вы должны приступить к реализации Factory.

Заводы также часто могут быть полезны для включения специализации типов через полиморфизм.

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

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

Использовать операции Factory как методы виртуального экземпляра чем статические, если они должны поддерживать полиморфное расширение.

Использовать шаблон Singleton для фабрик, основанных на экземплярах поскольку это не заставляет разработчиков создавать экземпляр типа Factory только для вызывают один из его членов.

Использовать метод Factory, если конструктор будет недостаточным для описывают выполняемую операцию и дополнительную информацию полученный от индивидуально названного Factory, выполняет операцию яснее.

Ответ 3

Статический метод Create может создавать и возвращать:

  • A MyClass экземпляр
  • Экземпляр любого подкласса MyClass
  • null

Ответ 4

Другой распространенный случай, когда методы factory помогают (на языках типа С# которые не поддерживают вывод типа из конструктора), - это когда вам нужно минимизировать спецификацию параметра типа, Рассмотрим общий случай класса Tuple. Вы можете:

new Tuple<int, int>(1, 1); //constructor call

или

Tuple.Create(1, 1); //factory pattern.

Ответ 5

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

Пример из .NET framework - это статические методы factory в классе Expression.

Ответ 6

Иногда важно вести бухгалтерский учет и/или управление ресурсами для каждого экземпляра созданного класса. В результате важно, чтобы каждая конструкция управлялась глобально, и статический метод для построения будет делать это красиво.

Ответ 7

Как вы можете видеть, myClass не следует "классическому" шаблону factory (где класс экземпляра неизвестен/открыт вне factory).

Однако в этом случае команда .NET framework может не стремиться к шаблону factory, но я думаю, что они не хотят, чтобы вы просто обновляли целевой класс напрямую с помощью имени файла через конструктор. A factory может быть излишним, если только этот класс предоставляется.

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

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

Ответ 8

Методы, которые делают для вас конструкцию, очень полезны для:

public class Class
    {
        public static List<Class> FromFiles(IEnumerable<String> paths)
        {
            List<Class> instances = new List<Class>();
            foreach (string path in paths)
            {
                instances.Add(new Class() { Path = path });
            }
            return instances;
        }

        public string Path { get; set; }
    }

... так как конструкторы "normal" не могут этого сделать.

Ответ 9

Вы можете использовать методы factory. Попытка карри построить конструктор дает вам: factory метод.

Я использую это в некоторых из моего кода, который перечисляет дерево диспетчера устройств Windows. В одном из классов перечислены последовательные порты, каждый последовательный порт имеет свойство соединения factory, которое возвращает метод curried factory с адресом порта (действительно уродливой строкой устройства PNP), хранящейся во внутреннем состоянии, в то время как скорость передачи, стоповые биты, паритет все предоставляется позже.

Ответ 10

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

Пример:

Assembly1.dll(не требует ссылки на BarAssembly.dll)
class Class1 { void Main(){ var foo = new Foo(); } }

Assembly2.dll(здесь нет необходимости ссылаться на BarAssembly.dll, поскольку CreateFoo и CreateFooWithBar не являются перегрузками)
class Class2 { void Main(){ var foo = CreateFoo(); } }

FooAssembly.dll(требуется ссылка на BarAssembly.dll)
class Foo { public CreateFoo(){ ... } public CreateFooWithBar(Bar bar){ ... } public Foo(){ ... } public Foo(Bar bar){ ... } }

BarAssembly.dll
class Bar { public Bar(){ ... } }

Примечание: Соблюдается в VS2013 здания против .NET Framework 4.5