Приветствую Вас, Гость · RSS Понедельник, 07.10.2024, 21:26










Главная » 2013 » Октябрь » 20 » Компоновщик (шаблон проектирования)
22:43
 

Компоновщик (шаблон проектирования)

Шаблон проектирования Компоновщик 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#

class MainApp { static void Main() { // Create a tree structure Component root = new Composite("root"); root.Add(new Leaf("Leaf A")); root.Add(new Leaf("Leaf B")); Component 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 Add(Component c); public abstract void Remove(Component c); public abstract void Display(int depth); } /// <summary> /// Composite - составной объект /// </summary> /// <li> /// <lu>определяет поведеление компонентов, у которых есть потомки;</lu> /// <lu>хранит компоненты-потомоки;</lu> /// <lu>реализует относящиеся к управлению потомками операции и интерфейсе /// класса <see cref="Component"/></lu> /// </li> class Composite : Component { private ArrayList children = new ArrayList(); // Constructor public Composite(string name) : base(name) { } public override void Add(Component component) { children.Add(component); } public override 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 Add(Component c) { Console.WriteLine("Cannot add to a leaf"); } public override void Remove(Component c) { Console.WriteLine("Cannot remove from a leaf"); } 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

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(); }

Пример на PHP5[править]

Исходный текст на языке PHP5

<?php // Component - компонент // объявляет интерфейс для компонуемых объектов; // предоставляет подходящую реализацию операций по умолчанию, // общую для всех классов; // объявляет интерфейс для доступа к потомкам и управлению ими; // определяет интерфейс доступа к родителю компонента в рекурсивной структуре // и при необходимости реализует его. Описанная возможность необязательна; abstract class Component { protected $name; // Constructor public function __construct($name) { $this->name = $name; } public abstract function add(Component $c); public abstract function remove(Component $c); public abstract function display(); } // Composite - составной объект // определяет поведение компонентов, у которых есть потомки; // хранит компоненты-потомоки; // реализует относящиеся к управлению потомками операции и интерфейс 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(); } } // Leaf - лист // представляет листовой узел композиции и не имеет потомков; // определяет поведение примитивных объектов в композиции; class Leaf extends Component { public function add(Component $c) { print ("Cannot add to a leaf"); } public function remove(Component $c) { print("Cannot remove from a leaf"); } 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(); }

Исходный текст на языке 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.
Просмотров: 2242 | Добавил: hamaget | Рейтинг: 0.0/0
Всего комментариев: 0
Создать бесплатный сайт с uCoz
Copyright MyCorp © 2024