Composite Pattern

From GPWiki
Jump to: navigation, search

How to combine several objects into an object that has the same behavior as its parts.

Definition

Problem

Consider a treasure chest in a RPG game. The chest can contain a selection of items for the player to pick up. But what if one of those items were to be another treasure chest, that also contained items of its own. The treasure chest would then both have to be a container and a containable item. The composite patterns teaches how to create such objects.

Context

  1. Primitive objects can be combined into composite objects
  2. Composite objects can be treated just as if they were primitive objects.

Solution

  1. Create an interface class that is an abstraction of the primitive.
  2. Both the primitive and composite objects must implement the interface.
  3. The composite object contains a list of primitive objects.
  4. When the one of the methods of the composite object is called it combines the result from all the containing primitives.


Formal class diagram of the composite pattern

Example Usage

Imagine programming an RPG game where you are an archer and use bow and arrow for your weapons. The arrows would be items that you can pick up and keep in your inventory. But having every arrow take up one slot in the inventory would quickly fill it, so instead we make it possible to keep multiple arrows in one slot by bundling them. However, the weight, sell value etc. of the bundle should reflect the arrows it's made by, so for that we use the composite programming pattern as illustrated below.

Class diagram of example usage of the composite pattern


Example pseudo code:

interface Arrow {
	String getDescription();
	int getWeight();
}
 
class StandardArrow implements Arrow {
	String getDescription() { return "Standard wooden arrow"; };
	int getWeight() { return 1 };
}
 
class FireArrow implements Arrow {
	String getDescription() { return "Flamable arrow that is lit before being shot"; };
	int getWeight() { return 2 };
}
 
class ArrowBundle implements Arrow {
	private List<Arrow> arrows;	
 
	void addArrow( Arrow a ) {
		arrows.add( a );
	}
 
	String getDescription()	{ return "Bundle of arrows"; };
 
	int getWeight() {
		int totalWeight = 0;
		for ( Arrow a : arrows ) {
			totalWeight += a.getWeight();
		}
		return totalWeight;
	}
}

Test:

displayInfo( new FireArrow() );
 
ArrowBundle ab = new ArrowBundle();
ab.addArrow( new StandardArrow() );
ab.addArrow( new FireArrow() );
ab.addArrow( new StandardArrow() );
displayInfo( ab );
 
ArrowBundle ab2 = new ArrowBundle();
ab2.addArrow( new FireArrow() );
ab2.addArrow( ab );
displayInfo( ab2 );
 
void displayInfo( Arrow a )
{
	println( "Information about the item" );
	println( "--------------------------" );
	println( a.getDescription() );
	println( "Weight: " + a.getWeight() );
}

Output:

Information about the item
--------------------------
Flamable arrow that are lit before shot
Weight: 2

Information about the item
--------------------------
Bundle of arrows
Weight: 4

Information about the item
--------------------------
Bundle of arrows
Weight: 6

Now arrows can be bundle and either added to the inventory a single arrows or in a bundle.

Additional Information