Composer ( eng. Composite pattern ) - a structural design template that combines objects in a tree structure to represent the hierarchy from private to whole. The linker allows clients to access individual objects and groups of objects in the same way.
| Linker | |
|---|---|
| Composite | |
| Type of | structural |
| Described in Design Patterns | Yes |
Content
- 1 Goal
- 2 Description
- 3 Implementation Examples
- 3.1 Java Example
- 3.2 C # Example
- 3.3 C ++ Example
- 3.4 Example on D
- 3.5 Python Example
- 3.6 PHP5 Example
- 3.7 Example linker with an external iterator in PHP5
- 3.8 PHP5.4 Example
- 3.9 CoffeeScript Example
- 3.10 Example on VB.NET
- 3.11 Delphi example
- 3.12 JavaScript Example
- 4 References
Purpose
The pattern defines a hierarchy of classes that can simultaneously consist of primitive and complex objects, simplifies the client architecture, makes the process of adding new types of objects easier.
Description
UML Template Diagram:
Implementation Examples
Java Example
Java source code
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 # Example
C # source code
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 - component
/// </summary>
/// <li>
/// <lu> declares an interface for composable objects; </lu>
/// <lu> provides a suitable implementation of the default operations,
/// common to all classes; </lu>
/// <lu> announces an interface for accessing and managing descendants; </lu>
/// <lu> defines the access interface to the component's parent in a recursive structure
/// and if necessary implements it. The feature described is optional; </lu>
/// </li>
abstract class Component
{
protected string name ;
// Constructor
public Component ( string name )
{
this . name = name ;
}
public abstract void Display ( int depth );
}
/// <summary>
/// Composite - a composite object
/// </summary>
/// <li>
/// <lu> defines the behavior of components that have children; </lu>
/// <lu> stores child components; </lu>
/// <lu> implements operations related to descendant management and the interface
/// class <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 - leaf
/// </summary>
/// <remarks>
/// <li>
/// <lu> represents the leaf node of the composition and has no descendants; </lu>
/// <lu> defines the behavior of primitive objects in the composition; </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 ++ Example
C ++ source code
#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 ;
}
Example D
D source code
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 example
Python source code
from abc import ABCMeta , abstractmethod
class Unit ( metaclass = ABCMeta ):
"" "
An abstract component, in this case it is a detachment (a detachment may
consist of one soldier or more)
"" "
@abstractmethod
def print ( self ) -> None :
"" "
Component output
"" "
pass
class Archer ( Unit ):
"" "
Archer
"" "
def print ( self ) -> None :
print ( 'archer' , end = '' )
class Knight ( Unit ):
"" "
Knight
"" "
def print ( self ) -> None :
print ( 'knight' , end = '' )
class Swordsman ( Unit ):
"" "
Swordsman
"" "
def print ( self ) -> None :
print ( 'swordsman' , end = '' )
class Squad ( Unit ):
"" "
Linker - a unit consisting of more than one person. Also
may include other squad units.
"" "
def __init__ ( self ):
self . _units = []
def print ( self ) -> None :
print ( "Order {} (" . format ( self . __hash__ ()), end = '' )
for u in self . _units :
u . print ()
print ( ')' )
def add ( self , unit : Unit ) -> None :
"" "
Adding a new squad
: param unit: squad (can be either a base unit or a linker)
"" "
self . _units . append ( unit )
unit . print ()
print ( 'joined squad {}' . format ( self . __hash__ ()))
print ()
def remove ( self , unit : Unit ) -> None :
"" "
Removing a squad from the current linker
: param unit: squad object
"" "
for u in self . _units :
if u == unit :
self . _units . remove ( u )
u . print ()
print ( 'left squad {}' . format ( self . __hash__ ()))
print ()
break
else :
unit . print ()
print ( 'not found in unit {}' . 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:
the knight joined squad -9223363262492103834
the knight joined squad -9223363262492103834
archer joined the unit -9223363262492103834
swordsman joined the unit -9223363262492103834
the swordsman left the unit -9223363262492103834
Squad -9223363262492103834 (knight archer knight)
swordsman joined squad 8774362671992
swordsman joined squad 8774362671992
Squad -9223363262492103834 (knight archer knight)
joined the squad 8774362671992
Detachment 8774362671992 (swordsman swordsman) Detachment -9223363262492103834 (knight archer knight)
)
'' '
PHP5 Example
PHP5 source code
<? 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 ();
?>
Example linker with an external iterator in PHP5
PHP5 source code
/ **
* Linker pattern with external iterator
* An iterator uses recursion to iterate over a tree of elements
* /
namespace compositeIterator {
/ **
* The client uses the AComponent interface to work with objects.
* AComponent interface defines an interface for all components: both combinations and leaf nodes.
* AComponent can implement default behavior for add () remove () getChild () and other operations
* /
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 inherits add () remove () getChild (which may not make sense for the leaf node.
* Although a leaf node can be considered a node with zero child objects
*
* Leaf determines the behavior of the elements of the combination. To do this, it implements operations supported by the Composite interface.
* /
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 interface defines the behavior of components that have child components, and provides storage of the latter.
*
* Composite also implements Leaf related operations. Some of them may not make sense for combinations; in such cases an exception is thrown.
* /
class Composite extends AComponent
{
private $ _iterator = null ;
/ **
* @var \ ArrayObject AComponent [] $ components for storing descendants of type 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 );
}
}
/ **
* Recursive linker 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 * /
// take the first element
$ 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 * /
// take the first element
$ componentsIterator = array_shift ( array_values ( $ this -> stack ));
return ( $ componentsIterator -> current ());
} else {
return ( null );
}
}
}
/ **
* The Iterator interface must be implemented by all iterators.
* This interface is part of the standard php iterator interface.
* A specific Iterator is responsible for managing the current iteration position in a particular collection.
* /
interface IPhpLikeIterator
{
/ **
* @abstract
* @return boolean is there a current item
* /
public function valid ();
/ **
* @abstract
* @return mixed move the cursor further
* /
public function next ();
/ **
* @abstract
* @return mixed get current item
* /
public function current ();
/ **
* delete the current item in the collection
* @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 example
PHP5.4 source code
<? 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 Example
CoffeeScript source code
An example of a simple physics engine disc
# 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 Example
VB.NET source code
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 - component
'' '</summary>
'' '<li>
'' '<lu> declares an interface for composable objects; </lu>
'' '<lu> provides a suitable implementation of default operations,
'' 'common to all classes; </lu>
'' '<lu> announces an interface for accessing and managing descendants; </lu>
'' '<lu> defines the access interface to the component's parent in a recursive structure
'' 'and if necessary implements it. The feature described is optional; </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 with As Component )
Public MustOverride Sub Remove ( ByVal with As Component )
Public MustOverride Sub Display ( ByVal depth As Integer )
End class
'' '<summary>
'' 'Composite - a composite object
'' '</summary>
'' '<li>
'' '<lu> defines the behavior of components that have children; </lu>
'' '<lu> stores child components; </lu>
'' '<lu> implements operations related to descendant management and the interface
'' 'of class <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 - leaf
'' '</summary>
'' '<remarks>
'' '<li>
'' '<lu> represents the leaf node of the composition and has no descendants; </lu>
'' '<lu> defines the behavior of primitive objects in the composition; </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 with As Component )
Console WriteLine ( "Cannot add to a leaf" )
End sub
Public Overrides Sub Remove ( ByVal with 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 example
Delphi source code
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 Example
JavaScript source
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 ;
// Application
var kitchen = new Composite ( 'Kitchen' );
kitchen . add ( new Leaf ( 'Upper Section' , 5200 ) );
kitchen . add ( new Leaf ( 'Upper Double Section' , 10000 ) );
kitchen . add ( new Leaf ( 'Lower section' , 4500 ) );
kitchen . add ( new Leaf ( 'Lower Corner Section' , 7800 ) );
var equipment = new Composite ( 'Technique' );
equipment . add ( new Leaf ( 'Gas stove' , 26400 ) );
equipment . add ( new Leaf ( 'Refrigerator' , 32300 ) );
equipment . add ( new Leaf ( 'Dishwasher' , 21600 ) );
kitchen . add ( equipment );
console . log ( 'Total:' + kitchen . execute () + 'rub.' );
Links
- Composite pattern (Composer) - purpose, description, implementation in C ++, advantages and disadvantages