Страницы

Поиск по вопросам

пятница, 29 ноября 2019 г.

Зачем нужен фабричный метод?

#c_sharp #шаблоны_проектирования


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

abstract class Creator
    {
        public abstract Product FactoryMethod();
    }

    class ConcreteCreatorA : Creator
    {
        public override Product FactoryMethod() { return new ConcreteProductA(); }
    }

    abstract class Product
    {}

    class ConcreteProductA : Product
    {}


Какая выгода нам от создания объекта через Creator, если точно так же можно его создать
через new? Когда нужно использовать именно фабричный метод, и какое преимущество нам
это может дать?
    


Ответы

Ответ 1



Выгод может быть много. Некоторые: Вы можете дать имя вашему конструктору. Например: Point PointCreator.FromPolar(double r, double phi) PointCreator.FromPolar читается намного лучше, чем new Point(1, 0). Раз уж вы даёте имя, вы можете иметь несколько конструкторов с одинаковыми сигнатурами: Point PointCreator.FromPolar(double r, double phi) { ... } Point PointCreator.FromCartesian(double x, double y) { ... } или например DateTime DateTime.FromSeconds(double seconds) { ... } DateTime DateTime.FromMilliseconds(double ms) { ... } Вы можете создавать объекты не данного типа, а любого производного, причём конкретный тип может быть скрыт внутри фабрики (так что у вашего остального кода не будет зависимости от этого конкретного типа). Вы можете сделать дополнительные действия после окончательного построения объекта. Например, вы можете зарегистрировать объект в списке всех активных объектов. С конструктором такое не очень удобно, т. к. вам придётся делать это либо в конструкторе базового класса, и выкладывать ссылку на недоконструированный объект (что может привести к понятным проблемам, если кто-то в этот момент обратится к объекту), либо дублировать код во всех потомках (что не всегда возможно, и непроверяемо, так что провоцирует баги). Или вы можете сделать дополнительную инициализацию свойств объекта, если вам это нужно: WebRequest InitWebRequest(string uri) { var request = WebRequest.Create(uri); request.Credentials = new NetworkCredential(Settings.Login, Settings.Password); return request; } Вы не можете сделать конструктор асинхронным, а фабричный метод — можете. В самом фабричном методе вы можете вызвать конструктор и async-метод для инициализации. async SerialDevice Create(PortInfo portInfo) { var device = new SerialDevice(portInfo); await device.Connect(); return device; }

Ответ 2



Проблема в самом операторе new. Используя его, вы каждый раз создаёте экземпляр конкретного типа. А фабричный метод позволяет абстрагироваться от конкретных типов и передать ответственность за создание экземпляров реализации этого паттерна. На выходе вы получаете некий абстрактный тип Product, который обладает теми или иными интересующими вас свойствами, но конкретная реализация которого вам не важна.

Комментариев нет:

Отправить комментарий