Шаблон проектирования для создания определенных элементов вида
Предположим, у нас есть абстрактная фабрика, которая создает для нас некоторые продукты. Мы знаем, что абстрактная фабрика может предоставить нам некоторые специфические подклассы продукта, но мы не хотим проверять тип (это основная причина этого шаблона). Теперь нам нужно создать конкретное представление для каждого типа объекта, как мы можем сделать это, не зная определенного типа? Должна ли одна и та же фабрика создавать разные виды?
Обновление: я создал репозиторий github, чтобы опробовать все разные подходы.
1 ответ
Для этой проблемы мы можем посмотреть, как абстрактный шаблон фабрики реализован в ADO.NET.
У нас есть абстрактная фабрика под названием DbProviderFactory
, Есть несколько реализаций этой фабрики, как SqlClientFactory
, MySqlClientFactory
, OracleClientFactory
и т.п.
Для этой проблемы продукты являются объектами, связанными с базой данных, такими как соединение, команда, адаптер данных и т. Д.
Сначала наша абстрактная фабрика дает нам связь (продукт). Возможно MySqlConnection
или же OracleConnection
, Единственное, что мы знаем, это DbConnection
,
DbProviderFactory factory = ...
DbConnection conn = factory.CreateConnection();
Теперь нам нужно создать командный объект (представление), который можно использовать вместе с этим соединением.
DbCommand cmd = conn.CreateCommand();
Как видите, команда (представление) создается соединением (продуктом), а не абстрактной фабрикой.
Но это не совсем так...
То, что происходит на самом деле, скрыто в деталях реализации. Когда абстрактная фабрика создает соединение, оно переходит к соединению. И когда мы запрашиваем команду, соединение создает команду через предоставленную абстрактную фабрику.
Итак, если мы вернемся к вашей проблеме, реализация может быть примерно такой.
interface IView {
IProduct Product { get; set; }
void Render();
}
interface IProduct {
IView CreateView();
}
interface IAbstractFactory {
IProduct CreateProduct();
IView CreateView();
}
class View1 : IView {
public IProduct Product { get; set; }
public void Render() {
Product1 p1 = (Product1)Product;
// Do product1 specific rendering here
}
}
class Product1 : IProduct {
private IAbstractFactory factory;
public Product1(IAbstractFactory factory) {
this.factory = factory;
}
public IView CreateView() {
IView view = factory.CreateView();
view.Product = this;
return this;
}
}
class Factory1 : IAbstractFactory {
IProduct CreateProduct() {
return new Product1(this);
}
IView CreateView() {
return new View1();
}
}