stringtranslate.com

Составной узор

В разработке программного обеспечения составной шаблон представляет собой шаблон проектирования секционирования . Составной шаблон описывает группу объектов, которые обрабатываются так же, как один экземпляр объекта того же типа. Целью композиции является «составление» объектов в древовидные структуры для представления иерархий части-целого. Реализация составного шаблона позволяет клиентам единообразно обрабатывать отдельные объекты и композиции. [1]

Обзор

Шаблон проектирования Композитный [2] — один из двадцати трех известных шаблонов проектирования GoF , которые описывают, как решать повторяющиеся проблемы проектирования для разработки гибкого и многократно используемого объектно-ориентированного программного обеспечения, то есть объектов, которые легче реализовать, изменить, тестируйте и используйте повторно.

Какие проблемы может решить шаблон проектирования «Композитный»?

При определении (1) Partобъектов и (2) Wholeобъектов, которые действуют как контейнеры для Partобъектов, клиенты должны обрабатывать их отдельно, что усложняет клиентский код. [3]

Какое решение описывает шаблон проектирования «Композитный»?

Это позволяет клиентам работать через Componentинтерфейс для единообразной обработки Leafобъектов Composite: Leafобъекты выполняют запрос напрямую, а Compositeобъекты пересылают запрос своим дочерним компонентам рекурсивно вниз по древовидной структуре. Это упрощает реализацию, изменение, тестирование и повторное использование клиентских классов.

См. также диаграмму классов и объектов UML ниже.

Мотивация

Имея дело с данными с древовидной структурой, программистам часто приходится различать листовой узел и ветвь. Это делает код более сложным и, следовательно, более подверженным ошибкам. Решением является интерфейс, позволяющий единообразно обрабатывать сложные и примитивные объекты. В объектно-ориентированном программировании составной объект — это объект, спроектированный как композиция одного или нескольких аналогичных объектов, обладающих схожей функциональностью. Это известно как отношение « имеет » между объектами. [4] Ключевая концепция заключается в том, что вы можете манипулировать одним экземпляром объекта так же, как если бы вы манипулировали их группой. Операции, которые вы можете выполнять со всеми составными объектами, часто имеют отношение наименьшего общего знаменателя . Например, при определении системы для отображения сгруппированных фигур на экране было бы полезно определить изменение размера группы фигур, чтобы оно имело тот же эффект (в некотором смысле), что и изменение размера одной фигуры.

Когда использовать

Композитный вариант следует использовать, когда клиенты игнорируют разницу между составами объектов и отдельными объектами. [1] Если программисты обнаруживают, что они используют несколько объектов одинаковым образом и часто имеют почти идентичный код для обработки каждого из них, тогда составной объект — хороший выбор; в этой ситуации проще рассматривать примитивы и составные элементы как однородные.

Состав

Диаграмма классов и объектов UML

Пример класса UML и объектной диаграммы для шаблона проектирования «Композитный». [5]

На приведенной выше диаграмме классов UML класс не ссылается на классы и напрямую (отдельно). Вместо этого термин относится к общему интерфейсу и может обрабатываться единообразно . Класс не имеет дочерних элементов и напрямую реализует интерфейс. Класс поддерживает контейнер дочерних объектов ( ) и перенаправляет к ним запросы ( ).ClientLeafCompositeClientComponentLeafComposite
LeafComponent
CompositeComponentchildrenchildrenfor each child in children: child.operation()

Диаграмма сотрудничества объектов показывает взаимодействие во время выполнения: В этом примере объект Clientотправляет запрос объекту верхнего уровня Composite(типа Component) в древовидной структуре. Запрос пересылается (выполняется) всем дочерним Componentобъектам ( Leafи Compositeобъектам) вниз по древовидной структуре.

Определение дочерних операций
Определение дочерних операций в шаблоне проектирования «Композит». [6]

Существует два варианта дизайна для определения и реализации дочерних операций, таких как добавление/удаление дочернего компонента в/из контейнера ( add(child)/remove(child)) и доступ к дочернему компоненту ( getChild()):

В шаблоне проектирования Composite основное внимание уделяется единообразию , а не безопасности типов .

Диаграмма классов UML

Составной шаблон в UML .
Компонент
Лист
Композитный
Составной узор в LePUS3.

Вариация

Как описано в разделе «Шаблоны проектирования» , этот шаблон также предполагает включение методов манипулирования дочерними элементами в основной интерфейс компонента, а не только в подкласс Composite. В более поздних описаниях эти методы иногда опускаются. [7]

Пример

Эта реализация C++14 основана на реализации до C++98, описанной в книге.

#include <iostream> #include < строка> #include <список> #include <память> #include <stdException>     typedef двойная валюта ;  // объявляет интерфейс для объектов в композиции. class Equipment { // Компонент public : // реализует поведение по умолчанию для интерфейса, общего для всех классов, в зависимости от ситуации. virtual const std :: string & getName () { возвращаемое имя ; } Virtual void setName ( const std :: string & name_ ) { name = name_ ; } виртуальная валюта getNetPrice () { return netPrice ; } Virtual void setNetPrice ( валюта netPrice_ ) { netPrice = netPrice_ ; } // объявляет интерфейс для доступа и управления дочерними компонентами. virtual void add ( std :: shared_ptr < Оборудование > ) = 0 ; виртуальная пустота удалить ( std :: shared_ptr < Оборудование > ) = 0 ; виртуальный ~ Оборудование () = по умолчанию ; protected : Equipment () : name ( "" ), netPrice ( 0 ) {} Equipment ( const std :: string & name_ ) : name ( name_ ), netPrice ( 0 ) {} Private : std :: string name ; Валюта чистая цена ; };                                                                   // определяет поведение компонентов, имеющих дочерние элементы. class CompositeEquipment : public Equipment { // Composite public : // реализует операции, связанные с дочерними элементами, в интерфейсе компонента. виртуальная валюта getNetPrice () переопределить { Общая сумма валюты = Оборудование :: getNetPrice ();                  for ( const auto & i : Equipment ) { total += i -> getNetPrice (); } Возвращаемая сумма ; } Virtual void add ( std :: shared_ptr < Оборудование > оборудование_ ) переопределить { оборудование . push_front ( оборудование_ . get ()); } Virtual void удалить ( std :: shared_ptr < Оборудование > оборудование_ ) переопределить { оборудование . удалить ( оборудование_ . получить ()); } protected : CompositeEquipment () : оборудование () {} CompositeEquipment ( const std :: string & name_ ) : оборудование () { setName ( name_ ); } Private : // сохраняет дочерние компоненты. std :: list < Оборудование *> оборудование ; };                                        // представляет листовые объекты в композиции. class FloppyDisk : public Equipment { // Leaf public : FloppyDisk ( const std :: string & name_ ) { setName ( name_ ); } // У листа нет детей. void add ( std :: shared_ptr < Оборудование > ) override { throw std :: runtime_error ( "FloppyDisk::add" ); } void Remove ( std :: shared_ptr < Оборудование > ) override { throw std :: runtime_error ( "FloppyDisk::remove" ); } };                           класс Chassis : public CompositeEquipment { public : Chassis ( const std :: string & name_ ) { setName ( name_ ); } };           int main () { // Интеллектуальные указатели предотвращают утечки памяти. std :: shared_ptr <FloppyDisk> fd1 = std :: make_shared <FloppyDisk> ( « 3,5-дюймовая дискета » ) ; fd1 -> setNetPrice ( 19.99 ); std :: cout << fd1 -> getName () << ": netPrice=" << fd1 -> getNetPrice () << '\n' ;                  std :: shared_ptr <FloppyDisk> fd2 = std :: make_shared <FloppyDisk> ( « 5.25in Floppy » ) ; fd2 -> setNetPrice ( 29,99 ); std :: cout << fd2 -> getName () << ": netPrice=" << fd2 -> getNetPrice () << '\n' ;              std :: unique_ptr < Шасси > ch = std :: make_unique < Шасси > ( "Шасси ПК" ); ч -> setNetPrice ( 39.99 ); ч -> добавить ( fd1 ); ч -> добавить ( fd2 ); std :: cout << ch -> getName () << ": netPrice=" << ch -> getNetPrice () << '\n' ;                fd2 -> добавить ( fd1 ); }

Вывод программы

3,5 на дискете : netPrice = 19,99 5,25 на дискете : netPrice = 29,99 Корпус ПК : netPrice = 89,97 завершить вызов после создания экземпляра ' std :: runtime_error ' What ( ) : FloppyDisk :: add               

Смотрите также

Рекомендации

  1. ^ аб Гамма, Эрих; Ричард Хелм; Ральф Джонсон; Джон М. Влиссидес (1995). Шаблоны проектирования: элементы объектно-ориентированного программного обеспечения многократного использования. Аддисон-Уэсли. стр. 395. ISBN 0-201-63361-2.
  2. ^ Эрих Гамма, Ричард Хелм, Ральф Джонсон, Джон Влиссидес (1994). Шаблоны проектирования: элементы объектно-ориентированного программного обеспечения многократного использования. Эддисон Уэсли. стр. 163 и далее. ISBN 0-201-63361-2.{{cite book}}: CS1 maint: несколько имен: список авторов ( ссылка )
  3. ^ «Шаблон составного проектирования — проблема, решение и применимость» . w3sDesign.com . Проверено 12 августа 2017 г.
  4. ^ Скотт Уолтерс (2004). Книга шаблонов проектирования Perl. Архивировано из оригинала 8 марта 2016 г. Проверено 18 января 2010 г.
  5. ^ «Композитный шаблон проектирования — структура и сотрудничество» . w3sDesign.com . Проверено 12 августа 2017 г.
  6. ^ «Шаблон составного проектирования — реализация» . w3sDesign.com . Проверено 12 августа 2017 г.
  7. Гири, Дэвид (13 сентября 2002 г.). «Взгляд на шаблон проектирования Composite». Шаблоны проектирования Java. JavaWorld . Проверено 20 июля 2020 г.

Внешние ссылки