В программной инженерии , то композитная модель является разделение шаблона дизайна . Составной шаблон описывает группу объектов, которые обрабатываются так же, как один экземпляр одного и того же типа объекта. Назначение композита состоит в том, чтобы «составить» объекты в древовидные структуры для представления иерархий «часть-целое». Реализация составного шаблона позволяет клиентам одинаково обрабатывать отдельные объекты и композиции. [1]
Обзор
Шаблон проектирования Composite [2] - один из двадцати трех хорошо известных шаблонов проектирования GoF, которые описывают, как решать повторяющиеся проблемы проектирования для разработки гибкого и многократно используемого объектно-ориентированного программного обеспечения, то есть объектов, которые легче реализовать, изменить, тестирование и повторное использование.
Какие проблемы может решить шаблон проектирования Composite? [3]
- Должна быть представлена иерархия «часть-целое», чтобы клиенты могли одинаково обращаться с частями и целыми объектами.
- Иерархия частично и полностью должна быть представлена в виде древовидной структуры.
При определении (1) Part
объектов и (2) Whole
объектов, которые действуют как контейнеры для Part
объектов, клиенты должны обрабатывать их отдельно, что усложняет клиентский код.
Какое решение описывает шаблон проектирования Composite?
- Определите единый
Component
интерфейс как дляLeaf
объектов part ( ), так и для объектов whole (Composite
). - Отдельные
Leaf
объекты реализуютComponent
интерфейс напрямую, аComposite
объекты пересылают запросы своим дочерним компонентам.
Это позволяет клиентам работать через Component
интерфейс для единообразного обращения Leaf
с Composite
объектами: Leaf
объекты выполняют запрос напрямую, а Composite
объекты рекурсивно направляют запрос своим дочерним компонентам вниз по древовидной структуре. Это упрощает реализацию, изменение, тестирование и повторное использование клиентских классов.
См. Также схему классов и объектов UML ниже.
Мотивация
При работе с данными с древовидной структурой программистам часто приходится различать листовой узел и ветвь. Это делает код более сложным и, следовательно, более подверженным ошибкам. Решение представляет собой интерфейс, позволяющий одинаково работать со сложными и примитивными объектами. В объектно-ориентированном программировании композит - это объект, спроектированный как композиция из одного или нескольких похожих объектов, каждый из которых обладает схожими функциями. Это известно как « есть-а » отношения между объектами. [4] Ключевая концепция заключается в том, что вы можете манипулировать одним экземпляром объекта так же, как вы бы манипулировали их группой. Операции, которые вы можете выполнять со всеми составными объектами, часто имеют отношение наименьшего общего знаменателя . Например, если вы определяете систему для отображения сгруппированных фигур на экране, было бы полезно определить изменение размера группы фигур, чтобы иметь тот же эффект (в некотором смысле), что и изменение размера одной фигуры.
Когда использовать
Composite следует использовать, когда клиенты игнорируют разницу между составами объектов и отдельными объектами. [1] Если программисты обнаруживают, что они используют несколько объектов одинаково и часто имеют почти идентичный код для обработки каждого из них, то составной вариант - хороший выбор; в этой ситуации менее сложно рассматривать примитивы и композиты как однородные.
Состав
Диаграмма классов и объектов UML
В приведенной выше UML - диаграмме класса , то Client
класс не относится к Leaf
и Composite
классам непосредственно (отдельно). Вместо этого Client
относится к общему Component
интерфейсу и может обрабатываться Leaf
и Composite
единообразно. Класс не имеет детей и реализует интерфейс непосредственно. Класс поддерживает контейнер дочерних объектов ( ) и перенаправляет запросы к ним ( ).Leaf
Component
Composite
Component
children
children
for each child in children: child.operation()
Диаграмма взаимодействия объектов показывает взаимодействия во время выполнения: в этом примере Client
объект отправляет запрос Composite
объекту верхнего уровня (типа Component
) в древовидной структуре. Запрос направляется (выполняется) всем дочерним Component
объектам ( Leaf
и Composite
объектам) вниз по древовидной структуре.
- Определение операций, связанных с дочерними элементами
Существует два варианта дизайна для определения и реализации дочерних операций, таких как добавление / удаление дочернего компонента в / из контейнера ( add(child)/remove(child)
) и доступ к дочернему компоненту ( getChild()
):
- Дизайн для единообразия: дочерние операции определены в
Component
интерфейсе. Это позволяет клиентам одинаково обращатьсяLeaf
сComposite
объектами и объектами. Но безопасность типов теряется, потому что клиенты могут выполнять операции, связанные с дочернимиLeaf
объектами. - Дизайн для обеспечения безопасности типов: дочерние операции определены только в
Composite
классе. Клиенты должны относитьсяLeaf
иComposite
возражать по-разному. Но безопасность типов достигается, потому что клиенты не могут выполнять операции, связанные с дочернимиLeaf
объектами.
Шаблон проектирования Composite делает упор на единообразие, а не на безопасность типов .
Диаграмма классов UML
- Составная часть
- это абстракция для всех компонентов, включая составные
- объявляет интерфейс для объектов в композиции
- (необязательно) определяет интерфейс для доступа к родительскому компоненту в рекурсивной структуре и реализует его, если это необходимо.
- Лист
- представляет листовые объекты в композиции
- реализует все методы Component
- Композитный
- представляет собой составной компонент (компонент, имеющий дочерние элементы)
- реализует методы для управления детьми
- реализует все методы Component, как правило, делегируя их своим потомкам
Вариация
Как описано в шаблонах проектирования , шаблон также включает в себя включение методов манипулирования дочерними элементами в основной интерфейс компонента, а не только в подкласс Composite. В более поздних описаниях эти методы иногда отсутствуют. [7]
Пример
В следующем примере, написанном на Java , реализуется графический класс, который может быть либо эллипсом, либо композицией из нескольких графических объектов. Каждый рисунок можно распечатать. В форме Бэкуса-Наура ,
Графика :: = эллипс | GraphicList GraphicList :: = пусто | Graphic GraphicList
Его можно расширить для реализации нескольких других форм (прямоугольник и т. Д.) И методов ( преобразование и т. Д.).
Ява
import java.util.ArrayList ;/ ** "Компонент" * / interface Graphic { // Печатает графику. public void print (); }/ ** "Composite" * / class CompositeGraphic реализует Graphic { // Коллекция дочерней графики. закрытый финальный список < Графика > childGraphics = new ArrayList <> (); // Добавляет графику в композицию. public void add ( Графическое изображение ) { childGraphics . добавить ( графический ); } // Это только shallowCopy public void add ( List < Graphic > compositGraphic ) { childGraphics . addAll ( compositGraphic ); } // Печатает графику. @Override public void print () { for ( Graphic graphic : childGraphics ) { graphic . печать (); // Делегирование } } }/ ** "Leaf" * / class Ellipse реализует Graphic { // Печатает графику. @Override public void print () { System . из . println ( "Эллипс" ); } }/ ** Клиент * / class CompositeDemo { public static void main ( String [] args ) { // Инициализируем четыре эллипса Ellipse ellipse1 = new Ellipse (); Эллипс ellipse2 = новый Эллипс (); Эллипс ellipse3 = новый Эллипс (); Эллипс ellipse4 = новый Эллипс (); // Создание двух композитов, содержащих эллипсы CompositeGraphic compositGraphic2 = new CompositeGraphic (); compositGraphic2 . добавить ( эллипс1 ); compositGraphic2 . добавить ( эллипс2 ); compositGraphic2 . добавить ( эллипс3 ); CompositeGraphic compositGraphic3 = new CompositeGraphic (); compositGraphic3 . добавить ( эллипс4 ); // Создаем еще одну графику, которая содержит две графики CompositeGraphic compositGraphic = new CompositeGraphic (); compositGraphic . добавить ( compositGraphic2 ); compositGraphic . добавить ( compositGraphic3 ); // Печатает всю графику (в четыре раза больше строки "Ellipse"). compositGraphic . печать (); } }
Смотрите также
Рекомендации
- ^ а б Гамма, Эрих; Ричард Хелм; Ральф Джонсон; Джон М. Влиссидес (1995). Шаблоны проектирования: элементы объектно-ориентированного программного обеспечения многократного использования . Эддисон-Уэсли. С. 395 . ISBN 0-201-63361-2.
- ^ Эрих Гамма, Ричард Хелм, Ральф Джонсон, Джон Влиссидес (1994). Шаблоны проектирования: элементы объектно-ориентированного программного обеспечения многократного использования . Эддисон Уэсли. стр. 163ff . ISBN 0-201-63361-2.CS1 maint: несколько имен: список авторов ( ссылка )
- ^ «Шаблон составного проектирования - проблема, решение и применимость» . w3sDesign.com . Проверено 12 августа 2017 .
- ^ Скотт Уолтерс (2004). Книга шаблонов дизайна Perl . Архивировано из оригинала на 2016-03-08 . Проверено 18 января 2010 .
- ^ «Шаблон составного дизайна - структура и взаимодействие» . w3sDesign.com . Проверено 12 августа 2017 .
- ^ «Шаблон составного проектирования - Реализация» . w3sDesign.com . Проверено 12 августа 2017 .
- ^ Гири, Дэвид (13 сентября 2002 г.). «Взгляните на шаблон проектирования Composite» . Шаблоны проектирования Java. JavaWorld . Проверено 20 июля 2020 .
Внешние ссылки
- Реализация составного шаблона в Java
- Описание составного паттерна из Портлендского репозитория паттернов
- Составной паттерн в UML и LePUS3, формальном языке моделирования
- Class :: Delegation на CPAN
- «Конец наследования: Автоматическая Пробег время Интерфейс здание для агрегированных объектов» от Павла Барановского
- PerfectJPattern Open Source Project , предоставляет компонентную реализацию составного шаблона на Java.
- [1] Постоянная реализация на основе Java.
- Составной шаблон дизайна