CodeLAB
на главную карта сайта обратная связь
каталог | задачи | паттерны | исходники | стат | форумы | ссылки
 гость
искать в
Главная >> Каталог задач >> Паттерны >> Порождающие >> Строитель (Builder)

<< назад
распечатать обсудить >>


Строитель (Builder)
реализации: java, количество: 6

Aвтор: this
Дата: 30.05.2007
Просмотров: 43217
Рейтинг: 0/0,0(0)
+
реализации(исходники) +добавить

Имя

«Паттерн
Builder» codelab.ru codelab.ru источник оригинал

Строитель – паттерн, конструирующий, собирающий объект. codelab.ru оригинал источник codelab.ru

Условия, Задача, Назначение

Отделяет конструирование сложного объекта от его модели, т.е содержания и представления. codelab.ru codelab.ru источник оригинал

Подробней. Есть клиент, которому часто нужно создавать различные, сложные объекты. При этом процесс создания всех этих объектов – протекает очень схожими этапами, так что можно очертить общий единый алгоритм, включающий выполнение всех возможных действий, которые только могут потребоваться для построения всех сложных объектов.

При этом важный момент – конструируемые сложные объекты в общем случае не схожи между собой, т.е. невозможно разумным образом как-то обобщить все эти создаваемые объекты в единую иерархию, объединить общие свойства и т.д. Более того – на самом деле, это и не нужно делать! В смысле – это никому не нужно: клиент всегда знает где, в каком месте и какой ему нужно создать объект и нет необходимости что-то унифицировать.

Таким образом, получаем: различные, сложные объекты, которые нужно создавать на разных этапах и фазах выполнения приложения, а также довольно схожие алгоритмы их конструирования. Поэтому, чтобы не дублировать похожие места кода создания объектов – было бы очень удобно объединить этот процесс в единый алгоритм (Director, распорядитель), способный создать любой из интересующих сложных объектов.

Дальше – т.к. объекты совершенно разные – необходимо чтобы каждый объект имел свое конкретное внутреннее представление (структуру), т.к. невозможно создать все эти объекты с одинаковым внутреннем представлением. И вот уже для этого – следует выделить еще одну сущность (Builder, строитель), отвечающую непосредственно уже за создание отдельных частей объекта. Эта сущность будет своя на каждый сложный объект, который может быть построен.

Мотивация

Для небольшого примера рассмотрим кодировщик, в который заложена возможность распознавания и чтения документа в формате RTF (RichTextFormat), должна также «уметь» преобразовывать его во многие другие форматы, например в простой ASCII-текст или в представление, которое можно отобразить в виджете для ввода текста. Однако число вероятных преобразований заранее неизвестно. Поэтому должна быть обеспечена возможность без труда добавлять новый конвертор. оригинал codelab.ru источник codelab.ru
Таким образом, нужно сконфигурировать класс RTFReader с помощью объекта TextConverter, который мог бы преобразовывать RTF в другой текстовый формат. При разборе документа в формате RTF класс RTFReader вызывает TextConverter для выполнения преобразования. Всякий раз, как RTFReader распознает лексему RTF (простой текст или управляющее слово), для ее преобразования объекту TextConverter посылается запрос. Объекты TextConverter отвечают как за преобразование данных, так и за представление лексемы в конкретном формате. источник оригинал codelab.ru codelab.ru
Подклассы TextConverter специализируются на различных преобразованиях и форматах. Например, ASCIIConverter игнорирует запросы на преобразование чего бы то ни было, кроме простого текста. С другой стороны, TeXConverter будет реализовывать все запросы для получения представления в формате редактора TJX, собирая по ходу необходимую информацию о стилях. A TextWidgetConverter станет строить сложный объект пользовательского интерфейса, который позволит пользователю просматривать и редактировать текст. codelab.ru оригинал источник codelab.ru

codelab.ru codelab.ru оригинал источник

Класс каждого конвертора принимает механизм создания и сборки сложного объекта и скрывает его за абстрактным интерфейсом. Конвертор отделен от загрузчика, который отвечает за синтаксический разбор RTF-документа. оригинал codelab.ru источник codelab.ru
В паттерне строитель абстрагированы все эти отношения. В нем любой класс источник codelab.ru codelab.ru оригинал
конвертора называется строителем, а загрузчик - распорядителем. В применении codelab.ru оригинал источник codelab.ru
к рассмотренному примеру строитель отделяет алгоритм интерпретации формата текста (т.е. анализатор RTF-документов) от того, как создается и представляется документ в преобразованном формате. Это позволяет повторно использовать алгоритм разбора, реализованный в RTFReader, для создания разных текстовых представлений RTF-документов; достаточно передать в RTFReader различные подклассы класса TextConverter. источник codelab.ru оригинал codelab.ru
оригинал источник codelab.ru codelab.ru

Признаки применения, использования паттерна Строитель (Builder)

Если: codelab.ru источник codelab.ru оригинал
  1. Алгоритм создания сложного объекта не должен зависеть от того, из каких частей состоит объект, и как они стыкуются между собой. оригинал codelab.ru codelab.ru источник
  2. Процесс конструирования должен позволять создавать различные представления результирующего объекта. codelab.ru codelab.ru источник оригинал

Решение

источник codelab.ru оригинал codelab.ru

codelab.ru оригинал codelab.ru источник

Участники паттерна Строитель (Builder)

оригинал codelab.ru codelab.ru источник

  1. Builder (TextConverter) – строитель, абстрактный класс.
    Содержит перечень всех возможных абстрактных методов для создания и стыковки частей различных объектов (продуктов). оригинал источник codelab.ru codelab.ru
  2. ConcreteBuilder (ASCIIConverter,TeXConverter,TextWidgetConverter) – конкретный строитель, занимающийся созданием какого-либо одного объекта (продукта).
    Конструирует и связывает вместе части продукта посредством реализации только тех абстракных методов интерфейса Builder, которые нужны для создания частей этого продукта. Кроме этого – определяет внутреннее представление этого сложного объекта и предоставляет интерфейс для его получения: GetASCIIText, GetTextWidget. codelab.ru codelab.ru источник оригинал
  3. Director (RTFReader) – распорядитель.
    Фиксированный, единый алгоритм создания любых продуктов, для которых имеется соответствующий Builder. Конструирует продукт пользуясь общим интерфейсом Builder-а. codelab.ru оригинал codelab.ru источник
  4. Product (ASCIIText, TeXText, TextWidget) – конечный продукт, построенный с помощью конкретного Builder-а.
    Представляет сложный конструируемый объект. ConcreteBuilder строит внутреннее представление продукта и определяет процесс его сборки. Помимо этого может включать классы, которые определяют составные части, в том числе интерфейсы для сборки конечного результата из частей. источник codelab.ru codelab.ru оригинал

Схема использования паттерна Строитель (Builder)

оригинал источник codelab.ru codelab.ru

  1. Клиент создает объект-распорядитель Director и конфигурирует его нужным объектом-строителем Builder codelab.ru оригинал источник codelab.ru
  2. Распорядитель уведомляет строителя о том, что нужно построить очередную часть продукта оригинал источник codelab.ru codelab.ru
  3. Строитель обрабатывает запросы распорядителя и добавляет новые части к продукту оригинал codelab.ru codelab.ru источник
  4. Клиент забирает продукт у строителя codelab.ru оригинал источник codelab.ru
Следующая диаграмма взаимодействий иллюстрирует взаимоотношения строителя и распорядителя с клиентом: codelab.ru codelab.ru оригинал источник

оригинал источник codelab.ru codelab.ru

Вопросы, касающиеся реализации паттерна Строитель (Builder)

Обычно существует абстрактный класс Builder, в котором определены операции для каждого компонента, который распорядитель может «попросить» создать. источник оригинал codelab.ru codelab.ru
По умолчанию эти операции ничего не делают. Но в классе конкретного строите- оригинал codelab.ru codelab.ru источник
ля ConcreteBuilder замещены те операции, которые необходимо будет вызывать для создания соответствующего объекта и формирования правильной его внутренней структуры. codelab.ru оригинал codelab.ru источник
Вот еще некоторые достойные внимания вопросы реализации: источник codelab.ru оригинал codelab.ru
  1. Интерфейсы сборки и конструирования.
    Строители конструируют свои продукты шаг за шагом. Поэтому интерфейс класса Builder должен быть достаточно общим, чтобы обеспечить конструирование при любом виде конкретного строителя.
    Ключевой вопрос проектирования связан с выбором модели процесса конструирования и сборки. Обычно бывает достаточно модели, в которой результаты выполнения запросов на конструирование просто добавляются к продукту. В примере с RTF-документами строитель преобразует и добавляет очередную лексему к уже конвертированному тексту. оригинал источник codelab.ru codelab.ru
  2. Почему нет абстрактного класса для продуктов?
    В типичном случае продукты, изготавливаемые различными строителями, имеют настолько разные представления, что изобретение для них общего родительского класса ничего не дает. В примере с RTF-документами трудно представить себе общий интерфейс у объектов ASCIIText и TextWidget, да он и не нужен. оригинал codelab.ru источник codelab.ru
  3. Поскольку клиент обычно конфигурирует распорядителя подходящим конкретным строителем, то, надо полагать, ему известно, какой именно подкласс класса Builder используется и как нужно обращаться с произведенными продуктами. codelab.ru оригинал источник codelab.ru

Результаты

Достоинства паттерна строитель (Builder): codelab.ru оригинал источник codelab.ru
  1. Позволяет задавать разное внутреннее представление продукта.
    Объект Director оперирует лишь абстрактным интерфейсом класса Builder для создания сложного продукта по его частям. За этим абстрактным интерфейсом может быть скрыто, в принципе, какое угодно внутреннее представление объекта. Как следствие – для изменения этого внутреннего представления, нужно лишь определить новый вид строителя. codelab.ru источник оригинал codelab.ru
  2. Отделяет процесс конструирования объектов от процесса создания их внутреннего представления.
    Паттерн строитель улучшает модульность, инкапсулируя способ конструирования и представления сложного объекта. Клиентам ничего не надо знать о классах, определяющих внутреннюю структуру продукта, они отсутствуют в интерфейсе строителя.
    Каждый конкретный строитель ConcreteBuilder содержит весь код, необходимый для создания и сборки конкретного вида продукта. Код пишется только один раз, после чего разные распорядители могут использовать его повторно для построения вариантов продукта из одних и тех же частей.
    В примере с RTF-документом мы могли бы определить загрузчик для формата, отличного от RTF, скажем, SGMLReader, и воспользоваться теми же самыми классами TextConverters для генерирования представлений SGML-документов в виде ASCII-текста, ТеХ-текста или текстового виджета. codelab.ru оригинал источник codelab.ru
  3. Дает полный, более тонкий контроль над процессом конструирования.
    В отличие от порождающих паттернов, которые сразу конструируют весь объект целиком, строитель делает это шаг за шагом под управлением распорядителя. И лишь когда продукт завершен, распорядитель забирает его у строителя. Поэтому интерфейс строителя в большей степени отражает процесс конструирования продукта, нежели другие порождающие паттерны. Это позволяет обеспечить более тонкий контроль над процессом конструирования, а значит, и над внутренней структурой готового продукта. codelab.ru codelab.ru оригинал источник

Пример

Рассмотрим реализацию сборочного конвейера автомобилей. Как известно по нему двигается сначала пустой кузов (каркас), и постепенно на каждом новом этапе к этому каркасу дособираются новые части. В общем случае на конвейере, в принципе, все-равно что собирать – грузовики, легковые и т.д.; главное чтобы соответствующие рабочие бригады выполняли свою работу последовательно на каждом этапе. codelab.ru оригинал codelab.ru источник

Поэтому последовательность наших действий, выполняемых конвейером(ProductionLine) может быть очень просто сведена к определенному всегда одинаковому сценарию: сборка, добавление дверей в авто, колес, двигателя и покраска (метод MakeCar()): ProductionLine.java codelab.ru источник codelab.ru оригинал

Соответственно, получим строитель, дающий возможность выполнять все эти действия: CarBuilder. codelab.ru источник codelab.ru оригинал

Все операции построения в классе CarBuilder по умолчанию ничего не делают. Но они не объявлены исключительно абстрактными, чтобы в производных классах можно было замещать лишь часть методов. источник codelab.ru оригинал codelab.ru

Теперь просто смотрим, какие авто нам нужно будет собирать и реализуем соответствующие строители. К счастью в данной ситуации нам нужны лишь «Десятки» и «КамАЗы», поэтому добавляем только: Vaz2110Builder, KamazBuilder. codelab.ru оригинал codelab.ru источник

Обратите внимание, как строитель скрывает внутреннее представление авто(CarBuilder), то есть классы колес, дверей, двигателя и т.д., и как эти части собираются вместе для завершения построения машины. Кто-то, может, и догадается, что для представления колес, дверей, двигателя – есть особые классы, но относительно остальных, например, трансмиссии, тормозной системы – нет даже намека. За счет этого становится проще модифицировать способ представления авто, поскольку ни одного из клиентов CarBuilder изменять не надо. codelab.ru codelab.ru источник оригинал
Как и другие порождающие паттерны, строитель инкапсулирует способ создания объектов (также как и инкапсулирует вспомогательные объекты, фигурирующие в этом процессе: трансмиссия, тормозная система и т.д.); в данном случае с помощью интерфейса, определенного классом CarBuilder. Это означает, что CarBuilder можно повторно использовать и для создания иных видов машин, например, спортивных. В рамках предметной области это выглядит тоже вполне жизненно: на том же контейнере мы начинаем собирать еще и спортивные авто (метод MakeSportCar()): ProductionLine codelab.ru источник codelab.ru оригинал
Мы могли бы поместить все операции класса KamazBuilder и Vaz2110Builder в класс Car и позволить каждому авто собирать себя самому. Но чем меньше класс, тем проще он для понимания и модификации, a Vaz2110Builder легко отделяется от Car. Еще важнее то, что разделение этих двух классов позволяет иметь множество разновидностей класса CarBuilder, в каждом из которых есть собственные классы для колес, дверей, сидений. codelab.ru codelab.ru оригинал источник
Но и это еще не все. Вы можете выполнять и различные другие бизнес операции с помощью все той же построенной архитектуры паттерна. Например, вот как вы можете без лишних перекомпиляций решить задачу подсчета движущихся частей в автомобиле: RotatingPartCountBuilder. источник codelab.ru codelab.ru оригинал
Обратите внимание, что традиционные операции сборки соответствующих частей (MakeDoor, MakeWheel) теперь вообще ничего не делают, кроме добавления предполагаемого количества вращающихся деталей, которые в них содержатся. А также обратите внимание на геттер getCount(), не определенный в интерфейсе CarBuilder конечно, т.к. это не нужно – когда мы хотим подсчитать количество вращающихся деталей авто, собираемых на данном конвейере, мы явно создаем RotatingPartCountBuilder и после всего процесса обращаемся к нему же за количеством через getCount(). источник codelab.ru codelab.ru оригинал
  codelab.ru источник оригинал codelab.ru
Вот как клиент мог бы все это использовать: Client codelab.ru оригинал codelab.ru источник


Реализации: java(6)   +добавить реализацию

1) Client.java, code #419[автор:this]
2) ProductionLine.java, code #414[автор:this]
3) CarBuilder.java, code #415[автор:this]
4) Vaz2110Builder.java, code #416[автор:this]
5) KamazBuilder.java, code #417[автор:this]
6) RotatingPartCountBuilder.java, code #418[автор:this]


<< назад наверх
распечатать обсудить >>

 
каталог | задачи | паттерны | исходники | стат | форумы | карта сайта | контакты | ссылки 
© 2000-2017 CodeLAB Group
  Все права защищены
Страница сгенерирована за 0.029293 секунд
Количество запросов к БД: 14, gzip: 18.9kb/98.8kb(81%)