Шаблон Prototype - это гораздо больше, чем шаблон Clone. Семантика клонирования является более широкой, то есть поля скаляров / значений одного экземпляра объекта дублируются в новом экземпляре, так что они имеют эквивалентное состояние, но занимают разные места в памяти. Клон можно использовать для удовлетворения самых разных потребностей.
Шаблон Prototype включает Clone специально для решения более крупной проблемы отделения конструкции объекта от использования объекта. Семантика прототипа утверждает, что единственный (или, по крайней мере, поддерживаемый / предпочтительный) метод для создания нового объекта требуемого поведения - это клонирование определенного экземпляра, известного как экземпляр прототипа. Эти экземпляры прототипа могут находиться на фабрике прототипов, которая реализована для создания новых экземпляров, вызывая Clone для экземпляров прототипа. Экземпляры прототипа могут быть инициализированы посредством внедрения зависимости. Инъекционный код - единственный код, который должен знать, как создавать экземпляры прототипа, и он фактически становится настоящим фабричным кодом.
Надеюсь, следующий пример фабричного класса проясняет суть шаблона:
public class PrototypeWidgetFactory : IWidgetFactory
{
public PrototypeWidgetFactory(PrototypeWidget scenarioA, PrototypeWidget scenarioB, PrototypeWidget scenarioC)
{
_scenarioA = scenarioA;
_scenarioB = scenarioB;
_scenarioC = scenarioC;
}
public Widget GetForScenarioA() { return _scenarioA.Clone(); }
public Widget GetForScenarioB() { return _scenarioB.Clone(); }
public Widget GetForScenarioC() { return _scenarioC.Clone(); }
private PrototypeWidgetFactory _scenarioA;
private PrototypeWidgetFactory _scenarioB;
private PrototypeWidgetFactory _scenarioC;
}
Экземпляр этой фабрики можно передавать везде, где требуется IWidgetFactory. Преимущество в том, что вам не нужно связывать разные классы фабрики для каждого поведения. Фактически, для определенных типов поведения вам даже не нужна куча разных классов, если вы просто внедряете экземпляры одного и того же типа, которые по-разному инициализируются, в фабрику прототипов. В этом случае преимущество еще больше в том, что API не раздувается с кучей небольших классов, которые мало что делают.
Недостаток заключается в том, что внедряемый код должен знать, как создавать прототипы. Это хрупко, если в создании прототипов задействовано много сложной логики.
(Примечание: шаблон Prototype не требует, чтобы все методы на фабрике прототипов возвращали один и тот же тип. Я только что сделал пример, возвращающий только виджеты, потому что это демонстрирует большее преимущество использования прототипов для создания объектов для конкретного поведения, когда объекты одного типа, но инициализируются по-другому.)
public class PrototypeDomainFactory : IDomainFactory
{
public PrototypeDomainFactory(PrototypePerson personPrototype, PrototypeCompany companyPrototype, PrototypeWidget widgetPrototype)
{
_personPrototype = personPrototype;
_companyPrototype = companyPrototype;
_widgetPrototype = widgetPrototype;
}
public Person GetPerson() { return _personPrototype.Clone(); }
public Company GetCompany() { return _companyPrototype.Clone(); }
public Widget GetWidget() { return _widgetPrototype.Clone(); }
private PrototypePerson _personPrototype;
private PrototypeCompany _companyPrototype;
private PrototypeWidget _widgetPrototype;
}