Компонувальник (шаблон проєктування)
Компонувальник, Composite — структурний шаблон який об'єднує об'єкти в ієрархічну деревоподібну структуру, і дозволяє уніфіковане звертання для кожного елемента дерева.
Дозволяє користувачам будувати складні структури з простіших компонентів. Проєктувальник може згрупувати дрібні компоненти для формування більших, які, в свою чергу, можуть стати основою для створення ще більших.

Ключем до паттерну компонувальник є абстрактний клас, який є одночасно і примітивом, і контейнером(Component). У ньому оголошені методи, специфічні для кожного виду об'єкта (такі як Operation) і загальні для всіх складових об'єктів, наприклад операції для доступу і управління нащадками. Підкласи Leaf визначає примітивні об'єкти, які не є контейнерами. У них операція Operation реалізована відповідно до їх специфічних потреб. Оскільки у примітивних об'єктів немає нащадків, то жоден з цих підкласів не реалізує операції, пов'язані з управління нащадками (Add, Remove, GetChild). Клас Composite складається з інших примітивніших об'єктів Component. Реалізована в ньому операція Operation викликає однойменну функцію відтворення для кожного нащадка, а операції для роботи з нащадками вже не порожні. Оскільки інтерфейс класу Composite відповідає інтерфейсу Component, то до складу об'єкта Composite можуть входити і інші такі ж об'єкти.
- Component (Component)
Оголошує інтерфейс для компонованих об'єктів; Надає відповідну реалізацію операцій за замовчуванням, загальну для всіх класів; Оголошує єдиний інтерфейс для доступу до нащадків та управління ними; Визначає інтерфейс для доступу до батька компонента в рекурсивної структурі і при необхідності реалізує його (можливість необов'язкова);
- Leaf (Leaf_1, Leaf_2) — лист.
Об'єкт того ж типу що і Composite, але без реалізації контейнерних функцій; Представляє листові вузли композиції і не має нащадків; Визначає поведінку примітивних об'єктів в композиції; Входить до складу контейнерних об'єктів;
- Composite (Composite) — складений об'єкт.
Визначає поведінку контейнерних об'єктів, у яких є нащадки; Зберігає ієрархію компонентів-нащадків; Реалізує пов'язані з управління нащадками (контейнерні) операції в інтерфейсі класу Component;
- Клієнти використовують інтерфейс класу компонентів для взаємодії з об'єктами у складній структурі.
- Якщо виклик здійснюється в листок, запит обробляється безпосередньо.
- Якщо виклик до Composite, він пересилає запит до своїх дочірніх компонентів.
- Як тільки деревоподібна структура визначена, композитний дизайн робить дерево надто загальним.
- У конкретних випадках важко обмежити компоненти дерева лише окремими типами.
- Для забезпечення обмеження програма повинна спиратися на перевірки виконання часу, оскільки вона не може використовувати систему типу мови програмування.
#include <iostream> #include <deque> using namespace std; // Інтерфейс компонентів struct IQuackable { virtual ~IQuackable() {} virtual void print() const = 0; }; // Конкретні компоненти struct Duck :public IQuackable { virtual void print() const { cout << "Duck " << '\n'; } }; struct MallardDuck :public Duck { virtual void print() const { cout << "Mallard Duck" << '\n'; } }; struct RedheadDuck :public Duck { virtual void print() const { cout << "Redhead Duck" << '\n'; } }; // Компонувальник // Також може бути компонентом class Flock : public IQuackable { protected: deque<IQuackable*> quackers;// контейнер компонентів public: virtual void print() const { for (size_t i = 0; i < quackers.size(); ++i) { quackers[i]->print();// псевдо-рекурсивний виклик } } void add(IQuackable* quacker) { quackers.push_back(quacker); } void remove(size_t i) { if (i < quackers.size()) { quackers.erase(quackers.begin() + i); } } }; void main() { Flock Gang; IQuackable* gang[3] = { new MallardDuck(), new RedheadDuck(), new MallardDuck() }; // додаємо компонувальнику компонентів for (int i = 0; i < 3; ++i) { Gang.add(gang[i]); } Flock* Ducks = new Flock; for (int i = 0; i < 3; ++i) { Ducks->add(new Duck()); } Gang.add(Ducks); // додаємо компонувальника, як компонент іншого компонувальника Gang.print(); }
// Composite pattern -- Structural example using System; using System.Collections.Generic; namespace DoFactory.GangOfFour.Composite.Structural { /// <summary> /// MainApp startup class for Structural /// Composite Design Pattern. /// </summary> class MainApp { /// <summary> /// Entry point into console application. /// </summary> static void Main() { // Create a tree structure Composite root = new Composite("root"); root.Add(new Leaf("Leaf A")); root.Add(new Leaf("Leaf B")); Composite comp = new Composite("Composite X"); comp.Add(new Leaf("Leaf XA")); comp.Add(new Leaf("Leaf XB")); root.Add(comp); root.Add(new Leaf("Leaf C")); // Add and remove a leaf Leaf leaf = new Leaf("Leaf D"); root.Add(leaf); root.Remove(leaf); // Recursively display tree root.Display(1); // Wait for user Console.ReadKey(); } } /// <summary> /// The 'Component' abstract class /// </summary> abstract class Component { protected string name; // Constructor public Component(string name) { this.name = name; } public abstract void Display(int depth); } /// <summary> /// The 'Composite' class /// </summary> class Composite : Component { private List<Component> _children = new List<Component>(); // Constructor public Composite(string name) : base(name) { } public void Add(Component component) { _children.Add(component); } public void Remove(Component component) { _children.Remove(component); } public override void Display(int depth) { Console.WriteLine(new String('-', depth) + name); // Recursively display child nodes foreach (Component component in _children) { component.Display(depth + 2); } } } /// <summary> /// The 'Leaf' class /// </summary> class Leaf : Component { // Constructor public Leaf(string name) : base(name) { } public override void Display(int depth) { Console.WriteLine(new String('-', depth) + name); } } }
- Gamma, Erich; Helm, Richard; Johnson, Ralph; Vlissides, John (1994). Design Patterns: Elements of Reusable Object-Oriented Software (вид. [1]). Addison–Wesley. с. 395.
{{cite book}}
: Зовнішнє посилання в
(довідка)(англ.)|edition=
- Alan Shallowey, James R. Trott (2004). Design Patterns Explained: A New Perspective on Object-Oriented Design (PDF).(англ.)
- http://www.dofactory.com/ [Архівовано 29 Квітня 2012 у Wayback Machine.]