Составной узор
В разработке программного обеспечения составной шаблон секционирования представляет собой шаблон проектирования . Составной шаблон описывает группу объектов, которые обрабатываются так же, как один экземпляр объекта того же типа. Целью композиции является «составление» объектов в древовидные структуры для представления иерархий части-целого. Реализация составного шаблона позволяет клиентам единообразно обрабатывать отдельные объекты и композиции. [1]
Обзор
[ редактировать ]![]() | Этот раздел может потребовать очистки Википедии , чтобы соответствовать стандартам качества . Конкретная проблема заключается в следующем: заголовки подразделов не должны дублировать заголовок статьи и не должны быть сформулированы как вопросы . Но точно ли эти заголовки описывают содержание подраздела? Если да, возможно, уместно изменить их на «Проблемы решены» и «Описано решение». ( Май 2024 г. ) |
Композитный [2] шаблон проектирования — один из двадцати трех известных Шаблоны проектирования GoF которые описывают, как решать повторяющиеся проблемы проектирования для разработки гибкого и многократно используемого объектно-ориентированного программного обеспечения, то есть объектов, которые легче реализовать, изменить, протестировать и повторно использовать.
Какие проблемы может решить шаблон проектирования «Композитный»?
[ редактировать ]- Иерархия часть-целое должна быть представлена так, чтобы клиенты могли единообразно обрабатывать части и целые объекты.
- Иерархию части-целого следует представлять в виде древовидной структуры.
При определении (1) Part
объекты и (2) Whole
объекты, которые действуют как контейнеры для Part
объекты, клиенты должны обрабатывать их отдельно, что усложняет клиентский код. [3]
Какое решение описывает шаблон проектирования «Композитный»?
[ редактировать ]- Определить единую
Component
интерфейс для обеих частей (Leaf
) предметы и целые (Composite
) объекты. - Индивидуальный
Leaf
объекты реализуютComponent
интерфейс напрямую иComposite
объекты пересылают запросы своим дочерним компонентам.
Это позволяет клиентам работать через Component
интерфейс для лечения Leaf
и Composite
объекты равномерно:
Leaf
объекты выполняют запрос напрямую,
и Composite
объекты
пересылать запрос своим дочерним компонентам рекурсивно вниз по древовидной структуре.
Это упрощает реализацию, изменение, тестирование и повторное использование клиентских классов.
См. также диаграмму классов и объектов UML ниже.
Мотивация
[ редактировать ]Имея дело с данными с древовидной структурой, программистам часто приходится различать листовой узел и ветвь. Это делает код более сложным и, следовательно, более подверженным ошибкам. Решением является интерфейс, позволяющий единообразно обрабатывать сложные и примитивные объекты. В объектно-ориентированном программировании составной объект — это объект, спроектированный как композиция одного или нескольких аналогичных объектов, обладающих схожей функциональностью. Это известно как отношение « имеет » между объектами. [4] Ключевая концепция заключается в том, что вы можете манипулировать одним экземпляром объекта так же, как если бы вы манипулировали их группой. Операции, которые вы можете выполнять со всеми составными объектами, часто имеют отношение наименьшего общего знаменателя . Например, при определении системы для отображения сгруппированных фигур на экране было бы полезно определить изменение размера группы фигур, чтобы оно имело тот же эффект (в некотором смысле), что и изменение размера одной фигуры.
Когда использовать
[ редактировать ]Композитный вариант следует использовать, когда клиенты игнорируют разницу между составами объектов и отдельными объектами. [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
[ редактировать ]
- Компонент
- — абстракция для всех компонентов, включая составные
- объявляет интерфейс для объектов в композиции
- (необязательно) определяет интерфейс для доступа к родительскому элементу компонента в рекурсивной структуре и реализует его, если это необходимо.
- Лист
- представляет листовые объекты в композиции
- реализует все методы компонента
- Композитный
- представляет составной компонент (компонент, имеющий дочерние элементы)
- реализует методы манипулирования детьми
- реализует все методы компонента, обычно делегируя их своим дочерним элементам.

Вариация
[ редактировать ]Как описано в разделе «Шаблоны проектирования» , этот шаблон также предполагает включение методов манипулирования дочерними элементами в основной интерфейс компонента, а не только в подкласс Composite. В более поздних описаниях эти методы иногда опускаются. [7]
Пример
[ редактировать ]Эта реализация C++14 основана на реализации до C++98, описанной в книге.
#include <iostream>
#include <string>
#include <list>
#include <memory>
#include <stdexcept>
typedef double Currency;
// declares the interface for objects in the composition.
class Equipment { // Component
public:
// implements default behavior for the interface common to all classes, as appropriate.
virtual const std::string& getName() {
return name;
}
virtual void setName(const std::string& name_) {
name = name_;
}
virtual Currency getNetPrice() {
return netPrice;
}
virtual void setNetPrice(Currency netPrice_) {
netPrice = netPrice_;
}
// declares an interface for accessing and managing its child components.
virtual void add(std::shared_ptr<Equipment>) = 0;
virtual void remove(std::shared_ptr<Equipment>) = 0;
virtual ~Equipment() = default;
protected:
Equipment() :name(""), netPrice(0) {}
Equipment(const std::string& name_) :name(name_), netPrice(0) {}
private:
std::string name;
Currency netPrice;
};
// defines behavior for components having children.
class CompositeEquipment : public Equipment { // Composite
public:
// implements child-related operations in the Component interface.
virtual Currency getNetPrice() override {
Currency total = Equipment::getNetPrice();
for (const auto& i:equipment) {
total += i->getNetPrice();
}
return total;
}
virtual void add(std::shared_ptr<Equipment> equipment_) override {
equipment.push_front(equipment_.get());
}
virtual void remove(std::shared_ptr<Equipment> equipment_) override {
equipment.remove(equipment_.get());
}
protected:
CompositeEquipment() :equipment() {}
CompositeEquipment(const std::string& name_) :equipment() {
setName(name_);
}
private:
// stores child components.
std::list<Equipment*> equipment;
};
// represents leaf objects in the composition.
class FloppyDisk : public Equipment { // Leaf
public:
FloppyDisk(const std::string& name_) {
setName(name_);
}
// A leaf has no children.
void add(std::shared_ptr<Equipment>) override {
throw std::runtime_error("FloppyDisk::add");
}
void remove(std::shared_ptr<Equipment>) override {
throw std::runtime_error("FloppyDisk::remove");
}
};
class Chassis : public CompositeEquipment {
public:
Chassis(const std::string& name_) {
setName(name_);
}
};
int main() {
// The smart pointers prevent memory leaks.
std::shared_ptr<FloppyDisk> fd1 = std::make_shared<FloppyDisk>("3.5in Floppy");
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<Chassis> ch = std::make_unique<Chassis>("PC Chassis");
ch->setNetPrice(39.99);
ch->add(fd1);
ch->add(fd2);
std::cout << ch->getName() << ": netPrice=" << ch->getNetPrice() << '\n';
fd2->add(fd1);
}
Вывод программы
3.5in Floppy: netPrice=19.99
5.25in Floppy: netPrice=29.99
PC Chassis: netPrice=89.97
terminate called after throwing an instance of 'std::runtime_error'
what(): FloppyDisk::add
См. также
[ редактировать ]Ссылки
[ редактировать ]- ^ Jump up to: а б Гамма, Эрих; Ричард Хелм; Ральф Джонсон; Джон М. Влиссидес (1995). Шаблоны проектирования: элементы объектно-ориентированного программного обеспечения многократного использования . Аддисон-Уэсли. стр. 395 . ISBN 0-201-63361-2 .
- ^ Эрих Гамма, Ричард Хелм, Ральф Джонсон, Джон Влиссидес (1994). Шаблоны проектирования: элементы объектно-ориентированного программного обеспечения многократного использования . Эддисон Уэсли. стр. 163 и далее . ISBN 0-201-63361-2 .
{{cite book}}
: CS1 maint: несколько имен: список авторов ( ссылка ) - ^ «Шаблон композитного проектирования — проблема, решение и применимость» . w3sDesign.com . Проверено 12 августа 2017 г.
- ^ Скотт Уолтерс (2004). Книга шаблонов проектирования Perl . Архивировано из оригинала 8 марта 2016 г. Проверено 18 января 2010 г.
- ^ «Шаблон проектирования «Композитный — структура и сотрудничество» . w3sDesign.com . Проверено 12 августа 2017 г.
- ^ «Шаблон проектирования «Композитный. Реализация» . w3sDesign.com . Проверено 12 августа 2017 г.
- ^ Гири, Дэвид (13 сентября 2002 г.). «Взгляд на шаблон проектирования Composite» . Шаблоны проектирования Java. JavaWorld . Проверено 20 июля 2020 г.
Внешние ссылки
[ редактировать ]
- составного шаблона в Java Реализация
- Описание составного шаблона из Портлендского репозитория шаблонов.
- Составной шаблон в UML и LePUS3, формальном языке моделирования.
- Класс::Делегирование в CPAN
- «Конец наследования: автоматическое создание интерфейса для агрегированных объектов во время выполнения», Пол Барановски
- Проект с открытым исходным кодом PerfectJPattern , обеспечивает компонентную реализацию составного шаблона на Java.
- [1] Постоянная реализация на основе Java
- Составной шаблон проектирования