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

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


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

Aвтор: this
Дата: 30.05.2007
Просмотров: 40561
Рейтинг: 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.039474 секунд
Количество запросов к БД: 14, gzip: 18.9kb/98.9kb(81%)