Страницы

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

четверг, 4 октября 2018 г.

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

Допустим есть вот такая реализация фабричного метода:
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? Когда нужно использовать именно фабричный метод, и какое преимущество нам это может дать?


Ответ

Выгод может быть много. Некоторые:
Вы можете дать имя вашему конструктору. Например:
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; }

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

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