Clever Geek Handbook
πŸ“œ ⬆️ ⬇️

Linker (design pattern)

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 ofstructural
Described in Design PatternsYes

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


Source - https://ru.wikipedia.org/w/index.php?title= Linker ( design_pattern )&oldid = 101356246


More articles:

  • Leishman, Melanie
  • Lyubartovich, Valery Anatolyevich
  • Urkumbaev, Mars Fazylovich
  • Diocese of Tara
  • Lesser mole rat
  • Kuchvaly
  • List of Zhukovsky schools
  • Navra (Kuyavian-Pomeranian Voivodeship)
  • Skompe (Kuyavian-Pomeranian Voivodeship)
  • Quad Hockey

All articles

Clever Geek | 2019