Шаблон проектирования: Строитель - PullRequest
24 голосов
/ 30 марта 2009

Я искал хороший пример шаблона Builder (в C #), но не могу найти его, потому что я не понимаю шаблон Builder или пытаюсь сделать то, что никогда не было предназначено. Например, если у меня есть методы абстрактного автомобиля и абстрактного конструктора для создания автомобильных деталей, я должен быть в состоянии отправить все 30 своих вариантов Директору, попросить его собрать нужные мне детали, а затем собрать свой автомобиль. Независимо от того, какой автомобиль, грузовик, полуприцеп и т. Д. Я должен был «вести» на нем точно так же.

Первая проблема - это большинство примеров значений свойств жесткого кода в конкретных частях, которые, на мой взгляд, должны исходить из базы данных. Я думал, что идея состояла в том, чтобы отправить свой выбор Директору (из источника данных) и попросить строителя создать индивидуальный продукт на основе моих данных.

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

Например, я хочу создать форму на лету, имея для меня поля формы изготовления Builder, включая метку, раздел ввода, проверку и т. Д. Таким образом, я могу прочитать объект из своего ORM, проверить метаданные объекта, передайте их моему Builder и добавьте вновь созданный результат управления пользователем в мою веб-форму.

Тем не менее, каждый пример Builder, который я нахожу, содержит только жестко закодированные данные, вместо того, чтобы передавать варианты выбора из основного кода в Builder и выкидывать настроенный продукт. Все, кажется, большой статический случай. Например, если у меня есть три параметра с 10 вариантами выбора, я не хочу создавать 30 конкретных методов Builder, я хочу создать только столько, сколько требуется для производства свойств, требуемых моему продукту, а это может быть только три.

Мне хочется, чтобы Директор существовал только в основном коде. Должен быть способ автоматически определять, какой конкретный метод конструктора вызывать аналогично полиморфизму и перегрузке методов (хотя это очень плохой пример), вместо использования оператора case в шаблоне. (Каждый раз, когда мне нужно добавить новый тип продукта, мне нужно будет изменить существующего директора, что плохо).

Ответы [ 4 ]

21 голосов
/ 30 марта 2009

В основном вызов BuilderPattern выглядит следующим образом:

Car car = new CarBuilder().withDoors(4).withColor("red").withABS(true).build();
14 голосов
/ 30 марта 2009

Я никогда не думал об этом таким образом, но LINQ (шаблон, а не синтаксис) на самом деле построитель, верно?

Это свободный интерфейс, который создает запрос и может создавать запросы в разных представлениях (SQL, запросы объектов в памяти, запросы веб-сервисов, Барт де Смет даже написал реализацию Linq-to-Excel).

11 голосов
/ 30 марта 2009

Я собираюсь обратиться к примеру C # в статье Википедии здесь .

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

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

Можно было бы сделать HawaiianPizzaBuilder. Когда класс инициализируется, он запрашивает в базе данных Гавайскую пиццу и получает строку. Затем при вызове различных методов Build (x) свойства будут установлены в соответствующем поле извлеченной строки базы данных.

Другой вариант - просто создать PizzaDatabaseBuilder и убедиться, что при инициализации класса вы передаете ему идентификатор строки, необходимой для пиццы этого типа. Например вместо

waiter.PizzaBuilder = new HawaiianPizzaBuilder();

Вы используете

waiter.PizzaBuilder = new PizzaDatabaseBuilder("Hawaiian");

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

Не должно быть проблемой. Вам нужен другой шаблон типа Factory / Builder для инициализации полей пиццы. Например

вместо

 public override void BuildDough()   { pizza.Dough   = "pan baked"; }

вы бы сделали что-то вроде

 public override void BuildDough()   { pizza.Dough   = new DoughBuilder("pan baked"); }

или

 public override void BuildDough()   { pizza.Dough   = new PanBakedDoughBuilder(); }

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

0 голосов
/ 30 марта 2009

Я бы сказал, что вы не можете избежать ни одного из них - иметь несколько перегрузок для ваших частей и иметь оператор case / if где-нибудь в стеке. Также единственной возможностью может быть изменение кода при добавлении нового класса.

Это значит, что вы можете получить помощь с некоторыми другими шаблонами, а именно с Фабрикой, которая может помочь вам в процессе строительства. Также разумное использование полиморфизма (например, все части наследуются от некоторого типа, будь то класс или интерфейс) может уменьшить количество ifs / case и перегрузок.

Надеюсь, это поможет.

...