Decorator Pattern – How to Add Functionality to Big Objects

clean codecompositiondesign-patterns

This question regards the usage of the Decorator pattern to add little functionality to objects of large classes.

Following the classic Decorator pattern, please consider the following class structure:

enter image description here

For example, imagine this happens inside a game. Instances of ConcreteCharacterDecorator are meant to add little functionality to the ConcreteCharacter they are 'wrapping'.

For instance, methodA() returns an int value representing the damage the character inflicts on enemies. The ConcreteCharacterDecorator simply adds to this value. Thus, it only needs to add code to methodA(). The functionality of methodB() stays the same.

ConcreteCharacterDecorator will look like this:

class ConcreteCharacterDecorator extends AbstractCharacterDecorator{

    ConcreteCharacter character;

    public ConcreteCharacterDecorator(ConcreteCharacter character){
        this.character = character;
    }

    public int methodA(){
        return 10 + character.methodA();
    }

    public int methodB(){
        character.methodB(); // simply delegate to the wrapped object.
    }

}

This is no problem with small classes containing two methods.

But what if AbstractCharacter defined 15 methods? ConcreteCharacterDecorator would have to implement all of them, even though it's only meant to add little functionality.

I will end up with a class containing one method that adds a little functionality, and another 14 methods that simply delegate to the inner object.

It would look like so:

class ConcreteCharacterDecorator extends AbstractCharacterDecorator{

    ConcreteCharacter character;

    public ConcreteCharacterDecorator(ConcreteCharacter character){
        this.character = character;
    }

    public int methodA(){
        return 10 + character.methodA();
    }

    public int methodB(){
        character.methodB(); // simply delegate to the wrapped object.
    }
    public int methodC(){
        character.methodC(); // simply delegate to the wrapped object.
    }
    public int methodD(){
        character.methodD(); // simply delegate to the wrapped object.
    }
    public int methodE(){
        character.methodE(); // simply delegate to the wrapped object.
    }
    public int methodF(){
        character.methodF(); // simply delegate to the wrapped object.
    }
    public int methodG(){
        character.methodG(); // simply delegate to the wrapped object.
    }
    public int methodH(){
        character.methodH(); // simply delegate to the wrapped object.
    }
    public int methodI(){
        character.methodI(); // simply delegate to the wrapped object.
    }
    public int methodJ(){
        character.methodJ(); // simply delegate to the wrapped object.
    }
    public int methodK(){
        character.methodK(); // simply delegate to the wrapped object.
    }
    public int methodL(){
        character.methodL(); // simply delegate to the wrapped object.
    }
    public int methodM(){
        character.methodM(); // simply delegate to the wrapped object.
    }
    public int methodN(){
        character.methodN(); // simply delegate to the wrapped object.
    }
    public int methodO(){
        character.methodO(); // simply delegate to the wrapped object.
    }

}

Obviously, very ugly.

I'm probably not the first to encounter this problem with the Decorator. How can I avoid this?

Best Answer

Quick and easy: AbstractCharacterDelegator does not have abstract functions, but virtual instead. By default, they pass through to the wrapped character and can be overridden. Then you inherit and only override the few you want.

This sort of thing isn't particularly useful unless you do quite a bit of decoration and your common interface is particularly wide. That shouldn't be too common. And this approach might not be by the letter a decorator, but it uses the concept and would be well understood to be a decorator by programmers that know the pattern.

Related Topic