The Decorator Design Pattern

How do we modify the behavior of methods in a pre-defined class?

If the class implements an interface, then we can use the Decorator Design Pattern.

Assume that the Character class implements the ICharacter interface.

We can introduce a second implementation of this interface called CharacterDecorator.

CharacterDecorator maintains a pointer to a peer that also implements the ICharacter interface.

All of the CharacterDecorator methods simply delegate to the peer:

CharacterDecorator implements ICharacter {
   protected ICharacter peer;
   public void attack(ICharacter victim) { peer.attack(victim); } // delegate to the peer
   // the rest are similar
}

Here's the design:

The implementation can be found in:

uw5/Tournament.java

Chaining

One of the advantages of the Decorator Pattern is that decorators can form chains that terminate with the non-decorator implementation.

For example, the Crusty character in Tournament.main is actually a chain of decorators. Here's how he attacks character c2:

This means characters can mix and match their attacking methods. This isn't possible with the Strategy Pattern.

The Strategy Pattern allows us to change the guts of an object. The Decorator Pattern allows us to change the skin of an object.

Adapters

But we cheated! In order to use the Decorator Pattern we needed to make several minor modifications in the Character class. What were they?

What do we do when a class like Character provides the required functionality, but doesn't implement the required interface, ICharacter?

The answer to this common problem is to use the Adapter Design Pattern.

An adapter implements the required interface by delegating to or calling methods inherited from the adaptee.

Here's our design using a class adapter:

 

Examine the implementation in:

uw5/uw5.1/Tournament.java

One problem is that the original Character.attack method expects its victim to be another character, not a decorator. To finesse this I needed to add a getCharacter method to the ICharacter interface. This method returns the character at the end of a chain of decorators.