The Replace Inheritance with Delegation refactoring (sometimes known as Replace Implementation Inheritance With Composition) provides a systematic way to replace inheritance hierarchies.
Inheritance hierarchies allow system designers to elegantly express relationships between different types of objects in a system. However, such hierarchies can be difficult to implement and refactor. Many developers favour restricting the use of inheritance hierarchies to very simple scenarios. If you started out using inheritance hierarchies (perhaps you had a simple scenario to start with) but are now finding the inheritance hierarchy is now getting in the way, apply this pattern.
Suppose we have the following property-centric class:
We might have a related class such as this:
For this simple case, we can stop here. For more complicated cases, the inheritance might start getting in the way. Here is how you can remove it using traditional delegation:
It looks like we have greatly increased the size of our code. This is because the earlier example was making using of Groovy's compact property notation which we can't use in this case. We should notice however, that most of this code is fairly boiler-plate in style.
Even though this example is not too bad, it becomes annoying to have to read, write and maintain this boiler-plate code. Instead, we can make use of Groovy's Meta-Programming capabilities as follows:
We can use the above classes with this script code:
With the result being:
The above example focussed on classes that were very data centric and were implemented using properties. Let's consider the a similar example but this time with classes which are method centric.
First, we define a
We can use inheritance to define a staff member class as follows:
This works well here, but in complex systems the inheritance might start to complicate our system. An alternative way to implement the functionality using traditional delegation is shown here:
The pattern here is simple, for each method in the delegate class that we want available in the staff member class, we create a method that explicitly calls the delegate. Simple but this is boiler-plate code that needs to change whenever we change the underlying classes.
So, as an alternative, we can use Groovy's Meta Object Programming facilities to auto delegate methods using
The result in this case looks like we didn't save much code at all. If however, there were lots of methods from the delegate that we needed to use, this one wouldn't grow in size, whereas the previous approach would become larger. Also, this version will require less maintenance as we don't need to explicitly change it if the
Person class changes over time. Note that because the
describe method didn't follow the boiler-plate approach of simple delegation (because it needed extra logic), we are still required to implement that method manually.
This script code shows the various classes described above in action:
Which results in the following output: