Компоновщик (шаблон проектирования)
Компоновщик | |
---|---|
Composite | |
Тип | структурный |
Описан в Design Patterns | Да |
Компоновщик (англ. Composite pattern) — структурный шаблон проектирования, объединяющий объекты в древовидную структуру для представления иерархии от частного к целому. Компоновщик позволяет клиентам обращаться к отдельным объектам и к группам объектов одинаково.
Цель
[править | править код]Паттерн определяет иерархию классов, которые одновременно могут состоять из примитивных и сложных объектов, упрощает архитектуру клиента, делает процесс добавления новых видов объекта более простым.
Описание
[править | править код]UML-диаграмма шаблона:
Примеры реализации
[править | править код]Пример на Java
[править | править код]Исходный текст на языке Java
import java.util.List;
import java.util.ArrayList;
/** "Component" */
interface Graphic {
//Prints the graphic.
public void print();
}
/** "Composite" */
class CompositeGraphic implements Graphic {
//Collection of child graphics.
private List<Graphic> mChildGraphics = new ArrayList<Graphic>();
//Prints the graphic.
public void print() {
for (Graphic graphic : mChildGraphics) {
graphic.print();
}
}
//Adds the graphic to the composition.
public void add(Graphic graphic) {
mChildGraphics.add(graphic);
}
//Removes the graphic from the composition.
public void remove(Graphic graphic) {
mChildGraphics.remove(graphic);
}
}
/** "Leaf" */
class Ellipse implements Graphic {
//Prints the graphic.
public void print() {
System.out.println("Ellipse");
}
}
/** Client */
public class Program {
public static void main(String[] args) {
//Initialize four ellipses
Ellipse ellipse1 = new Ellipse();
Ellipse ellipse2 = new Ellipse();
Ellipse ellipse3 = new Ellipse();
Ellipse ellipse4 = new Ellipse();
//Initialize three composite graphics
CompositeGraphic graphic = new CompositeGraphic();
CompositeGraphic graphic1 = new CompositeGraphic();
CompositeGraphic graphic2 = new CompositeGraphic();
//Composes the graphics
graphic1.add(ellipse1);
graphic1.add(ellipse2);
graphic1.add(ellipse3);
graphic2.add(ellipse4);
graphic.add(graphic1);
graphic.add(graphic2);
//Prints the complete graphic (four times the string "Ellipse").
graphic.print();
}
}
Пример на C#
[править | править код]Исходный текст на языке C#
class MainApp
{
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.Read();
}
}
/// <summary>
/// Component - компонент
/// </summary>
/// <li>
/// <lu>объявляет интерфейс для компонуемых объектов;</lu>
/// <lu>предоставляет подходящую реализацию операций по умолчанию,
/// общую для всех классов;</lu>
/// <lu>объявляет интерфейс для доступа к потомкам и управлению ими;</lu>
/// <lu>определяет интерфейс доступа к родителю компонента в рекурсивной структуре
/// и при необходимости реализует его. Описанная возможность необязательна;</lu>
/// </li>
abstract class Component
{
protected string name;
// Constructor
public Component(string name)
{
this.name = name;
}
public abstract void Display(int depth);
}
/// <summary>
/// Composite - составной объект
/// </summary>
/// <li>
/// <lu>определяет поведение компонентов, у которых есть потомки;</lu>
/// <lu>хранит компоненты-потомоки;</lu>
/// <lu>реализует относящиеся к управлению потомками операции и интерфейсе
/// класса <see cref="Component"/></lu>
/// </li>
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>
/// Leaf - лист
/// </summary>
/// <remarks>
/// <li>
/// <lu>представляет листовой узел композиции и не имеет потомков;</lu>
/// <lu>определяет поведение примитивных объектов в композиции;</lu>
/// </li>
/// </remarks>
class Leaf : Component
{
// Constructor
public Leaf(string name) : base(name)
{
}
public override void Display(int depth)
{
Console.WriteLine(new String('-', depth) + name);
}
}
Пример на C++
[править | править код]Исходный текст на языке C++
#include <iostream>
#include <list>
#include <algorithm>
#include <memory>
class IText{
public:
typedef std::shared_ptr<IText> SPtr;
virtual void draw() = 0;
virtual void add(const SPtr&) {
throw std::runtime_error("IText: Can't add to a leaf");
}
virtual void remove(const SPtr&){
throw std::runtime_error("IText: Can't remove from a leaf");
}
};
class CompositeText: public IText{
public:
void add(const SPtr& sptr){
children_.push_back(sptr);
}
void remove(const SPtr& sptr){
children_.remove(sptr);
}
void replace(const SPtr& oldValue, const SPtr& newValue){
std::replace(children_.begin(), children_.end(), oldValue, newValue);
}
virtual void draw(){
for(SPtr& sptr : children_){
sptr->draw();
}
}
private:
std::list<SPtr> children_;
};
class Letter: public IText{
public:
Letter(char c):c_(c) {}
virtual void draw(){
std::cout<<c_;
}
private:
char c_;
};
int main(){
CompositeText sentence;
IText::SPtr lSpace(new Letter(' '));
IText::SPtr lExcl(new Letter('!'));
IText::SPtr lComma(new Letter(','));
IText::SPtr lNewLine(new Letter('\n'));
IText::SPtr lH(new Letter('H')); // letter 'H'
IText::SPtr le(new Letter('e')); // letter 'e'
IText::SPtr ll(new Letter('l')); // letter 'l'
IText::SPtr lo(new Letter('o')); // letter 'o'
IText::SPtr lW(new Letter('W')); // letter 'W'
IText::SPtr lr(new Letter('r')); // letter 'r'
IText::SPtr ld(new Letter('d')); // letter 'd'
IText::SPtr li(new Letter('i')); // letter 'i'
IText::SPtr wHello(new CompositeText);
wHello->add(lH);
wHello->add(le);
wHello->add(ll);
wHello->add(ll);
wHello->add(lo);
IText::SPtr wWorld(new CompositeText); // word "World"
wWorld->add(lW);
wWorld->add(lo);
wWorld->add(lr);
wWorld->add(ll);
wWorld->add(ld);
sentence.add(wHello);
sentence.add(lComma);
sentence.add(lSpace);
sentence.add(wWorld);
sentence.add(lExcl);
sentence.add(lNewLine);
sentence.draw(); // prints "Hello, World!\n"
IText::SPtr wHi(new CompositeText); // word "Hi"
wHi->add(lH);
wHi->add(li);
sentence.replace(wHello, wHi);
sentence.draw(); // prints "Hi, World!\n"
sentence.remove(wWorld);
sentence.remove(lSpace);
sentence.remove(lComma);
sentence.draw(); // prints "Hi!\n"
return 0;
}
Пример на D
[править | править код]Исходный текст на языке D
import std.stdio;
abstract class TInfo
{
protected:
string name;
public:
void Info();
}
class TFile: TInfo
{
protected:
uint size;
public:
this(const string theName, uint theSize)
{
name = theName;
size = theSize;
}
void Info()
{
writefln("%s\t%d", name, size);
}
}
class TDir: TInfo
{
protected:
TInfo[] info;
public:
this(const string theName)
{
name = theName;
}
void Info()
{
writefln("[%s]", name);
foreach (f; info)
{
f.Info();
}
}
void Add(TInfo theInfo)
{
info ~= theInfo;
}
}
void main()
{
TDir first = new TDir("first");
first.Add(new TFile("a.txt", 100));
first.Add(new TFile("b.txt", 200));
first.Add(new TFile("c.txt", 300));
TDir second = new TDir("second");
second.Add(new TFile("d.txt", 400));
second.Add(new TFile("e.txt", 500));
TDir root = new TDir("root");
root.Add(first);
root.Add(second);
root.Info();
}
Пример на Python
[править | править код]Исходный текст на языке Python
from abc import ABCMeta, abstractmethod
class Unit(metaclass=ABCMeta):
"""
Абстрактный компонент, в данном случае это - отряд (отряд может
состоять из одного солдата или более)
"""
@abstractmethod
def print(self) -> None:
"""
Вывод данных о компоненте
"""
pass
class Archer(Unit):
"""
Лучник
"""
def print(self) -> None:
print('лучник', end=' ')
class Knight(Unit):
"""
Рыцарь
"""
def print(self) -> None:
print('рыцарь', end=' ')
class Swordsman(Unit):
"""
Мечник
"""
def print(self) -> None:
print('мечник', end=' ')
class Squad(Unit):
"""
Компоновщик - отряд, состоящий более чем из одного человека. Также
может включать в себя другие отряды-компоновщики.
"""
def __init__(self):
self._units = []
def print(self) -> None:
print("Отряд {} (".format(self.__hash__()), end=' ')
for u in self._units:
u.print()
print(')')
def add(self, unit: Unit) -> None:
"""
Добавление нового отряда
:param unit: отряд (может быть как базовым, так и компоновщиком)
"""
self._units.append(unit)
unit.print()
print('присоединился к отряду {}'.format(self.__hash__()))
print()
def remove(self, unit: Unit) -> None:
"""
Удаление отряда из текущего компоновщика
:param unit: объект отряда
"""
for u in self._units:
if u == unit:
self._units.remove(u)
u.print()
print('покинул отряд {}'.format(self.__hash__()))
print()
break
else:
unit.print()
print('в отряде {} не найден'.format(self.__hash__()))
print()
if __name__ == '__main__':
print('OUTPUT:')
squad = Squad()
squad.add(Knight())
squad.add(Knight())
squad.add(Archer())
swordsman = Swordsman()
squad.add(swordsman)
squad.remove(swordsman)
squad.print()
squad_big = Squad()
squad_big.add(Swordsman())
squad_big.add(Swordsman())
squad_big.add(squad)
squad_big.print()
'''
OUTPUT:
рыцарь присоединился к отряду -9223363262492103834
рыцарь присоединился к отряду -9223363262492103834
лучник присоединился к отряду -9223363262492103834
мечник присоединился к отряду -9223363262492103834
мечник покинул отряд -9223363262492103834
Отряд -9223363262492103834 ( рыцарь рыцарь лучник )
мечник присоединился к отряду 8774362671992
мечник присоединился к отряду 8774362671992
Отряд -9223363262492103834 ( рыцарь рыцарь лучник )
присоединился к отряду 8774362671992
Отряд 8774362671992 ( мечник мечник Отряд -9223363262492103834 ( рыцарь рыцарь лучник )
)
'''
Пример на PHP5
[править | править код]Исходный текст на языке PHP5
<?php
abstract class Component
{
protected $name;
public function __construct($name)
{
$this->name = $name;
}
public abstract function display();
}
class Composite extends Component
{
private $children = array();
public function add(Component $component)
{
$this->children[$component->name] = $component;
}
public function remove(Component $component)
{
unset($this->children[$component->name]);
}
public function display()
{
foreach($this->children as $child) {
$child->display();
}
}
}
class Leaf extends Component
{
public function display()
{
print_r($this->name);
}
}
// Create a tree structure
$root = new Composite("root");
$root->add(new Leaf("Leaf A"));
$root->add(new Leaf("Leaf B"));
$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 = new Leaf("Leaf D");
$root->add($leaf);
$root->remove($leaf);
// Recursively display tree
$root->display();
?>
Пример компоновщика с внешним итератором на PHP5
[править | править код]Исходный текст на языке PHP5
/**
* Паттерн-компоновщик с внешним итератором
* Итератор использует рекурсию для перебора дерева элементов
*/
namespace compositeIterator{
/**
* Клиент использует интерфейс AComponent для работы с объектами.
* Интерфейс AComponent определяет интерфейс для всех компонентов: как комбинаций, так и листовых узлов.
* AComponent может реализовать поведение по умолчанию для add() remove() getChild() и других операций
*/
abstract class AComponent
{
public $customPropertyName;
public $customPropertyDescription;
/**
* @param AComponent $component
*/
public function add($component)
{
throw new \Exception("Unsupported operation");
}
/**
* @param AComponent $component
*/
public function remove($component)
{
throw new \Exception("Unsupported operation");
}
/**
* @param int $int
*/
public function getChild($int)
{
throw new \Exception("Unsupported operation");
}
/**
* @return IPhpLikeIterator
*/
abstract function createIterator();
public function operation1()
{
throw new \Exception("Unsupported operation");
}
}
/**
* Leaf наследует методы add() remove() getChild( которые могут не иметь смысла для листового узла.
* Хотя листовой узел можно считать узлом с нулём дочерних объектов
*
* Leaf определяет поведение элементов комбинации. Для этого он реализует операции, поддерживаемые интерфейсом Composite.
*/
class Leaf extends AComponent
{
public function __construct($name, $description = '')
{
$this->customPropertyName = $name;
$this->customPropertyDescription = $description;
}
public function createIterator()
{
return new NullIterator();
}
public function operation1()
{
echo ("\n I'am leaf {$this->customPropertyName}, i don't want to do operation 1. {$this->customPropertyDescription}");
}
}
class NullIterator implements IPhpLikeIterator
{
public function valid()
{
return (false);
}
public function next()
{
return (false);
}
public function current()
{
return (null);
}
public function remove()
{
throw new \CException('unsupported operation');
}
}
/**
* Интерфейс Composite определяет поведение компонентов, имеющих дочерние компоненты, и обеспечивает хранение последних.
*
* Composite также реализует операции, относящиеся к Leaf. Некоторые из них не могут не иметь смысла для комбинаций; в таких случаях генерируется исключение.
*/
class Composite extends AComponent
{
private $_iterator = null;
/**
* @var \ArrayObject AComponent[] $components для хранения потомков типа AComponent
*/
public $components = null;
public function __construct($name, $description = '')
{
$this->customPropertyName = $name;
$this->customPropertyDescription = $description;
}
/**
* @param AComponent $component
*/
public function add($component)
{
if (is_null($this->components)) {
$this->components = new \ArrayObject;
}
$this->components->append($component);
}
public function remove($component)
{
foreach ($this->components as $i => $c) {
if ($c === $component) {
unset($this->components[$i]);
}
}
}
public function getChild($int)
{
return ($this->components[$int]);
}
public function operation1()
{
echo "\n\n $this->customPropertyName $this->customPropertyDescription";
echo "\n --------------------------------";
$iterator = $this->components->getIterator();
while ($iterator->valid()) {
$component = $iterator->current();
$component->operation1();
$iterator->next();
}
}
/**
* @return CompositeIterator
*/
public function createIterator()
{
if (is_null($this->_iterator)) {
$this->_iterator = new CompositeIterator($this->components->getIterator());
}
return ($this->_iterator);
}
}
/**
* Рекурсивный итератор компоновщика
*/
class CompositeIterator implements IPhpLikeIterator
{
public $stack = array();
/**
* @param \ArrayIterator $componentsIterator
*/
public function __construct($componentsIterator)
{
//$this->stack= new \ArrayObject;
$this->stack[] = $componentsIterator;
}
public function remove()
{
throw new \CException('unsupported operation');
}
public function valid()
{
if (empty($this->stack)) {
return (false);
} else {
/** @var $componentsIterator \ArrayIterator */
// берём первый элемент
$componentsIterator = array_shift(array_values($this->stack));
if ($componentsIterator->valid()) {
return (true);
} else {
array_shift($this->stack);
return ($this->valid());
}
}
}
public function next()
{
/** @var $componentsIterator \ArrayIterator */
$componentsIterator = current($this->stack);
$component = $componentsIterator->current();
if ($component instanceof Composite) {
array_push($this->stack, $component->createIterator());
}
$componentsIterator->next();
//return($component);
}
public function current()
{
if ($this->valid()) {
/** @var $componentsIterator \ArrayIterator */
// берём первый элемент
$componentsIterator = array_shift(array_values($this->stack));
return ($componentsIterator->current());
} else {
return (null);
}
}
}
/**
* Интерфейс Iterator должен быть реализован всеми итераторами.
* Данный интерфейс является частью интерфейса стандартного php итератора.
* Конкретный Iterator отвечает за управление текущей позицией перебора в конкретной коллекции.
*/
interface IPhpLikeIterator
{
/**
* @abstract
* @return boolean есть ли текущий элемент
*/
public function valid();
/**
* @abstract
* @return mixed перевести курсор дальше
*/
public function next();
/**
* @abstract
* @return mixed получить текущий элемент
*/
public function current();
/**
* удалить текущий элемент коллекции
* @abstract
* @return void
*/
public function remove();
}
class Client
{
/**
* @var AComponent
*/
public $topItem;
public function __construct($topItem)
{
$this->topItem = $topItem;
}
public function printOperation1()
{
$this->topItem->operation1();
}
public function printOperation2()
{
echo "\n\n\n";
$iterator = $this->topItem->createIterator();
while ($iterator->valid()) {
/** @var $component AComponent */
$component = $iterator->current();
if (strstr($component->customPropertyName, 'leaf1')) {
echo ("\n I'm Client, I found leaf {$component->customPropertyName}, I'll just leave it here (for my 'first-leafs' tea collection). {$component->customPropertyDescription}");
}
$iterator->next();
}
}
}
class Test
{
public static function go()
{
$a = new Composite("c1");
$b = new Composite("c2");
$c = new Composite("c3");
$topItem = new Composite("top item");
$topItem->add($a);
$topItem->add($b);
$topItem->add($c);
$a->add(new Leaf("c1-leaf1"));
$a->add(new Leaf("c1-leaf2"));
$b->add(new Leaf("c2-leaf1"));
$b->add(new Leaf("c2-leaf2"));
$b->add(new Leaf("c2-leaf3"));
$c->add(new Leaf("c3-leaf1"));
$c->add(new Leaf("c3-leaf2"));
$client = new Client($topItem);
$client->printOperation1();
$client->printOperation2();
}
}
Test::go();
}
Пример на PHP5.4
[править | править код]Исходный текст на языке PHP5.4
<?php
interface IComponent {
function display();
}
trait TComponent
{
public $name;
public function __construct($name)
{
$this->name = $name;
}
public function display()
{
print $this->name.'<br>'.PHP_EOL;
}
}
trait TComposite
{
use TComponent{
TComponent::display as displaySelf;
}
protected $children = array();
public function add(IComponent $item)
{
$this->children[$item->name] = $item;
}
public function remove(IComponent $item)
{
unset($this->children[$item->name]);
}
public function display()
{
$this->displaySelf();
foreach ($this->children as $child) {
$child->display();
}
}
}
class Composite implements IComponent
{
use TComposite;
}
class Leaf implements IComponent
{
use TComponent;
}
$root = new Composite("root");
$root->add(new Leaf("Leaf A"));
$root->add(new Leaf("Leaf B"));
$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"));
$leaf = new Leaf("Leaf D");
$root->add($leaf);
$root->remove($leaf);
$root->display();
Пример на CoffeeScript
[править | править код]Исходный текст на языке CoffeeScript
Пример болванки простенького физического движка
# Component
class PObject
collide : (pObj) ->
addChild : (pObj) ->
rmChild : (index) ->
getChild : (index) ->
# Leaf
class PShape extends PObject
collide : (pObj) ->
# ...
# Composite
class PCollection extends PObject
constructor : ->
@children = []
collide : (pObj) ->
child.collide(pObj) for child in @children
return @
addChild : (pObj) ->
@children.push(pObj) if pObj instanceof PObject
return @
rmChild : (index) ->
@children.splice(index, 1)
return @
getChild : (index) ->
@children[index]
Пример на VB.NET
[править | править код]Исходный текст на языке VB.NET
Class Program
Shared Sub Main()
' Create a tree structure
Dim root As Component = New Composite("root")
root.Add(New Leaf("Leaf A"))
root.Add(New Leaf("Leaf B"))
Dim comp As Component = 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
Dim leaf As New Leaf("Leaf D")
root.Add(leaf)
root.Remove(leaf)
' Recursively display tree
root.Display(1)
' Wait for user
Console.Read()
End Sub
End Class
''' <summary>
''' Component - компонент
''' </summary>
''' <li>
''' <lu>объявляет интерфейс для компонуемых объектов;</lu>
''' <lu>предоставляет подходящую реализацию операций по умолчанию,
''' общую для всех классов;</lu>
''' <lu>объявляет интерфейс для доступа к потомкам и управлению ими;</lu>
''' <lu>определяет интерфейс доступа к родителю компонента в рекурсивной структуре
''' и при необходимости реализует его. Описанная возможность необязательна;</lu>
''' </li>
MustInherit Class Component
Protected name As String
' Constructor
Public Sub New(ByVal name As String)
Me.name = name
End Sub
Public MustOverride Sub Add(ByVal c As Component)
Public MustOverride Sub Remove(ByVal c As Component)
Public MustOverride Sub Display(ByVal depth As Integer)
End Class
''' <summary>
''' Composite - составной объект
''' </summary>
''' <li>
''' <lu>определяет поведеление компонентов, у которых есть потомки;</lu>
''' <lu>хранит компоненты-потомоки;</lu>
''' <lu>реализует относящиеся к управлению потомками операции и интерфейсе
''' класса <see cref="Component"/></lu>
''' </li>
Class Composite
Inherits Component
Private children As New ArrayList()
' Constructor
Public Sub New(ByVal name As String)
MyBase.New(name)
End Sub
Public Overrides Sub Add(ByVal component As Component)
children.Add(component)
End Sub
Public Overrides Sub Remove(ByVal component As Component)
children.Remove(component)
End Sub
Public Overrides Sub Display(ByVal depth As Integer)
Console.WriteLine(New String("-"c, depth) & name)
' Recursively display child nodes
For Each component As Component In children
component.Display(depth + 2)
Next
End Sub
End Class
''' <summary>
''' Leaf - лист
''' </summary>
''' <remarks>
''' <li>
''' <lu>представляет листовой узел композиции и не имеет потомков;</lu>
''' <lu>определяет поведение примитивных объектов в композиции;</lu>
''' </li>
''' </remarks>
Class Leaf
Inherits Component
' Constructor
Public Sub New(ByVal name As String)
MyBase.New(name)
End Sub
Public Overrides Sub Add(ByVal c As Component)
Console.WriteLine("Cannot add to a leaf")
End Sub
Public Overrides Sub Remove(ByVal c As Component)
Console.WriteLine("Cannot remove from a leaf")
End Sub
Public Overrides Sub Display(ByVal depth As Integer)
Console.WriteLine(New String("-"c, depth) & name)
End Sub
End Class
Пример на Delphi
[править | править код]Исходный текст на языке Delphi
program CompositePattern;
{$APPTYPE CONSOLE}
uses
SysUtils, Contnrs;
type
TCustomLetter = class
public
procedure Draw; virtual; abstract;
end;
type
TLetter = class(TCustomLetter)
private
FLetter: Char;
public
constructor Create(aLetter: Char);
procedure Draw; override;
end;
constructor TLetter.Create(aLetter: Char);
begin
FLetter := aLetter;
end;
procedure TLetter.Draw;
begin
Write(FLetter);
end;
type
TWord = class(TCustomLetter)
private
FWord: String;
public
constructor Create(aWord: String);
procedure Draw; override;
end;
constructor TWord.Create(aWord: String);
begin
FWord := aWord;
end;
procedure TWord.Draw;
begin
Write(FWord);
end;
type
TText = class(TCustomLetter)
private
FList: TObjectList;
public
constructor Create;
destructor Destroy; override;
procedure Add(aCustomLetter: TCustomLetter);
procedure Draw; override;
end;
constructor TText.Create;
begin
inherited;
FList := TObjectList.Create;
end;
destructor TText.Destroy;
begin
FList.Free;
inherited;
end;
procedure TText.Add(aCustomLetter: TCustomLetter);
begin
FList.Add(aCustomLetter);
end;
procedure TText.Draw;
var
vI: Integer;
begin
for vI := 0 to Pred(FList.Count) do
TLetter(FList[vI]).Draw;
end;
var
vRootText, vSubText: TText;
begin
vRootText := TText.Create;
vSubText := TText.Create;
try
vSubText.Add(TLetter.Create('!'));
vSubText.Add(TLetter.Create('!'));
vSubText.Add(TLetter.Create('!'));
vSubText.Add(TWord.Create(' =)'));
vRootText.Add(TLetter.Create('H'));
vRootText.Add(TLetter.Create('E'));
vRootText.Add(TLetter.Create('L'));
vRootText.Add(TLetter.Create('L'));
vRootText.Add(TLetter.Create('O'));
vRootText.Add(TLetter.Create(' '));
vRootText.Add(TWord.Create('World'));
vRootText.Add(vSubText);
vRootText.Draw;
finally
vRootText.Destroy;
end;
ReadLn;
end.
Пример на JavaScript
[править | править код]Исходный текст на языке JavaScript
function Component() {
this.name = '';
this.value = 0;
this.execute = function () { };
}
function Leaf(name, value) {
this.name = name;
this.value = value;
this.execute = function () {
return this.value;
};
}
Leaf.prototype = Object.create(Component.prototype);
Leaf.prototype.constructor = Leaf;
function Composite(name) {
var self = this;
var children = [];
this.name = name;
this.add = function (component) {
children.push(component);
};
this.remove = function (componentName) {
var newChildren = [];
children.forEach(function (component) {
if (component.name !== componentName) {
newChildren.push(component);
}
});
children = newChildren;
};
this.execute = function () {
children.forEach(function (component) {
self.value = (self.value || 0) + component.execute();
});
return self.value;
};
}
Composite.prototype = Object.create(Component.prototype);
Composite.prototype.constructor = Composite;
// Применение
var kitchen = new Composite('Кухня');
kitchen.add( new Leaf('Верхняя секция', 5200) );
kitchen.add( new Leaf('Верхняя двойная секция', 10000) );
kitchen.add( new Leaf('Нижняя секция', 4500) );
kitchen.add( new Leaf('Нижняя угловая секция', 7800) );
var equipment = new Composite('Техника');
equipment.add( new Leaf('Газовая плита', 26400) );
equipment.add( new Leaf('Холодильник', 32300) );
equipment.add( new Leaf('Посудомойка', 21600) );
kitchen.add(equipment);
console.log('Итого: ' + kitchen.execute() + ' руб.');
Пример на Swift
[править | править код]Исходный текст на языке Swift
protocol Item {
var id: UInt32 { get }
var name: String { get }
func desctiption() -> String
}
class Button: Item {
var id: UInt32 = arc4random()
var name: String = "Button"
func desctiption() -> String {
return "ID: \(id) | \(name)"
}
}
class Label: Item {
var id: UInt32 = arc4random()
var name: String = "Label"
func desctiption() -> String {
return "ID: \(id) | \(name)"
}
}
class View: Item {
var components: [Item] = []
var id: UInt32 = arc4random()
var name: String = "View"
func desctiption() -> String {
return components.reduce("", {"\($0) \($1.desctiption())"})
}
func add(item: Item) {
components.append(item)
}
func remove(item: Item) {
if let index = components.firstIndex(where: {$0.id == item.id}) {
components.remove(at: index)
}
}
}
// Use Composite
let button = Button()
print(button.desctiption())
let view = View()
view.add(item: Button())
view.add(item: Label())
print(view.desctiption())
Ссылки
[править | править код]- Паттерн Composite (Компоновщик) — назначение, описание, реализация на C++, достоинства и недостатки