Компонувальник (шаблон проєктування)

Компонувальник, 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, він пересилає запит до своїх дочірніх компонентів.

Вади

  • Як тільки деревоподібна структура визначена, композитний дизайн робить дерево надто загальним.
  • У конкретних випадках важко обмежити компоненти дерева лише окремими типами.
  • Для забезпечення обмеження програма повинна спиратися на перевірки виконання часу, оскільки вона не може використовувати систему типу мови програмування.

Приклад реалізації

C++

Приклад реалізації на мові С++
#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();
}

C#

Приклад реалізації на мові С#
// 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.]


Prefix: a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9

Portal di Ensiklopedia Dunia

Kembali kehalaman sebelumnya