Компоновщик (шаблон проектирования)
Материал из Википедии — свободной энциклопедии
(перенаправлено с «Composite»)
| Компоновщик | |
| 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 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 <boost/shared_ptr.hpp> #include <boost/foreach.hpp> struct IText{ typedef boost::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"); } }; struct CompositeText: public IText{ 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(){ BOOST_FOREACH(SPtr& sptr, children_){ sptr->draw(); } } private: std::list<SPtr> children_; }; struct Letter: public IText{ 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(); }
[править] Пример на PHP5
Исходный текст на языке PHP5
<?php // Component - компонент // объявляет интерфейс для компонуемых объектов; // предоставляет подходящую реализацию операций по умолчанию, // общую для всех классов; // объявляет интерфейс для доступа к потомкам и управлению ими; // определяет интерфейс доступа к родителю компонента в рекурсивной структуре // и при необходимости реализует его. Описанная возможность необязательна; abstract class Component { protected $name; // Constructor public function Component($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() { print_r ($this->children); } } // 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(); ?>
[править] Пример на 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, Classes; type TCustomLetter = class public procedure Draw; virtual; abstract; end; type TLetter = class(TCustomLetter) private FLettrer: Char; public constructor Create(aLetter: Char); procedure Draw; override; end; constructor TLetter.Create(aLetter: Char); begin FLettrer:= aLetter; end; procedure TLetter.Draw; begin Write(FLettrer); 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: TList; public constructor Create; destructor Destroy; procedure Add(aCustomLetter: TCustomLetter); procedure Draw; override; end; constructor TText.Create; begin inherited; FList:= TList.Create; end; destructor TText.Destroy; var vI: Integer; begin for vI := 0 to Pred(FList.Count) do TLetter(FList[vI]).Destroy; 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 vText: TText; vSubText: TText; begin vText:= TText.Create; vSubText:= TText.Create; with vSubText do begin Add(TLetter.Create('!')); Add(TLetter.Create('!')); Add(TLetter.Create('!')); Add(TWord.Create(' =)')); end; with vText do begin Add(TLetter.Create('H')); Add(TLetter.Create('E')); Add(TLetter.Create('L')); Add(TLetter.Create('L')); Add(TLetter.Create('O')); Add(TLetter.Create(' ')); Add(TWord.Create('World')); Add(vSubText); Draw; end; vText.Destroy; ReadLn; end.
[править] Ссылки
- Паттерн Composite (Компоновщик) — назначение, описание, реализация на С++, достоинства и недостатки
| Это заготовка статьи по информатике. Вы можете помочь проекту, исправив и дополнив её. |

