Design Patterns - Decorator Pattern
Following up on the Observer/Event Pattern, it's time for the third pattern, the Decorator Pattern.
The definition: "Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality."
Continuing on our little game, let's say we are able to create buildings and have just an IBuilding interface and one building.
Each building has a description and a given power usage cost, which is simply hardcoded in the class right now.
After a while, our boss hired an external company to take over development with regards to the buildings and tasked them with making buildings upgradeable.
The first approach they took was too simply add new building classes to the game, for each possible upgrade.
This however leads to an infinite amount of possibilities and a nightmare to maintain.
If we look at the definition of the Decorator Pattern, it seems to offer a good alternative to all this inheriting to add in new functionality.
Also, adding additional responsibilities dynamically means we don't have to change the code of the IBuilding and NormalBuilding either. By doing this we are honoring the Open/Closed Principle, which says "software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification".
How are we going to add these additional things dynamically? We'll decorate our initial NormalBuilding with upgrades, giving us flexibility to equip a building with any upgrade combination we like.
When we mention decorating, think about wrapping. We are going to wrap an instance of IBuilding in a decorator, acting as a shell around the class, passing calls to our decorator along to the wrapped instance, modifying the results when needed.
It's also possible to chain decorators together, making it possible to decorate a NormalBuilding with two Turrets, a SAM installation and a Laser. This is done because a decorated object is still of the type IBuilding, and can be decorated again and again.
Eventually we'll end up with the following class diagram. Note, the WrappedBuilding has a protected getter and a private setter.
Now we have a set of buildings, which implement IBuilding and one decorator base class, BuildingUpgradeDecorator, from which all possible decorations inherit. This decorator class has to implement IBuilding as well, so it can be re-decorated.
With the above classes, it's possible to compose buildings as we desire, as shown below.
When we run this code, the call to the Power property is being passed through all decorators to the lowest level, our NormalBuilding, and returned all the way back, getting incremented with the additional power usage for each decorator/upgrade in the mean time.
I've uploaded the solution again so you can have a look on how the decorator base class and individual decorators are programmed.
Some additional information on the Decorator pattern: