a good example of favouring Composition over Inheritance
mob vs commando
Inheritance doesn't work in real life
During my Computer Science studies, I learned about a cliche example of Student and Teacher classes should inherit from a Person base class. All the common properties and methods should be put in the base class, therefore when new common properties and methods are added, they will not be duplicated in different child classes.
In reality, this almost never happens. I always hear about 'oh, the Item, Promotion and Award class all have ID, Price, Category and Redeem() method, only Promotion and Award have the same implementation for Redeem(). Item works differently'. A developer often creates deep tree of inheritance to solve this issue, trying to cascade the proper behavior down the inheritance tree. This is all fine and well until the next set of business requirement changes come in, which doesn't fit the tree and everything becomes a refactoring nightmare.
Composition does
This is the reason why composition is always better than inheritance. On a class level this means we should favor Interface over Class inheritance. Look at the following example:
public interface ICanEnrol { void Enrol(); } public interface IHaveAccount { void PayAccount(); void SendNotice(); } public class Student : ICanEnrol, IHaveAccount { ... }
As the characteristic of student increases, new interfaces can be added. Each of the new Service will only need to know about a specific interface rather than the whole inheritance hierarchy. The design is alot more loosely coupled than if it was relying on inheritance. There's no need for overloading a behavior.
Now this is the issue, with interface, we're only enforcing a characteristic of a class, not the implementation of the behavior. Copying pasting similar behavior to different classes obviously violates the DRY principle (Don't Repeat Yourself).
Inheriting the Behavior
I'm currently doing a small pet project which I struggle to find time to do using the Facebook Developer ToolKit framework (FDT). And I've learned a new small (but useful) compositional technique to replace class inheritance, without violating DRY.
The idea is to use small non-static helper classes that can be injected as the implementation of all the behaviors of an interface. This non-static helper classes are often called as Strategy.
Let's look at how to implement the previous example
public class BasicEnrolmentStrategy { public void Enrol() { ... } } public class OfficeAccountingStrategy { public void PayAccount() { ... } public void SendNotice() { ... } }
We have a couple of small strategies to be used by the Student class or any other class that share the same behavior.
The idea is: to never have a StudentEnrolmentStrategy. Doing so suggests that the strategy is going to never be shared with another class, say Teacher for example.
We want to keep the strategy name as close as possible to the behavior and not the owner of the behavior. Student and Teachers may have Basic Enrolment Strategy, but Principals and Janitor may have Additional Step Enrolment Strategy (as they need to do additional steps to enrol themselves into a school). You get the idea, right?
Let's look at how to inject these strategy into the class
public class Student : ICanEnrol, IHaveAccount { private BasicEnrolmentStrategy enrolment; private OfficeAccountingStrategy account; public Student() { enrolment = new BasicEnrolmentStrategy(); account = new OfficeAccountingStrategy(); } public void Enrol() { enrolment.Enrol(); } public void PayAccount() { account.PayAccount(); } public void SendNotice() { account.SendNotice(); } }
As you see, each of the method in the student class simply forward the call to the strategy. There are a couple of things that can be improved here:
- Create an interface for the enrolment strategy or use the ones available. So instead of declaring the behavior as BasicEnrolmentStrategy, we should declare it as ICanEnrol. This way the strategies can be easily interchangeable.
- Allow the strategies to be injected from the constructor (Inversion of control). This will make the class even more so compositional. Different strategies can be injected on run-time.
As a side effect, suddenly the student class is more testable. Look at asp.net MVC without the framework part 2 post (watch out for this upcoming post) to cover more about how to use inversion of control to do interaction based unit testing.
Reference
What you just describe seems a lot like Strategy Pattern.
www.dofactory.com/.../PatternStrategy
Hi Ricardo, indeed. It's 'merely' a strategy pattern.
I think what makes it interesting is in its usage. The fact that an entity class have more than one 1 strategy pattern, makes it alot more composable and a good 'replacement' technique to inheritance in a lot of cases.
Superb : )
I like the way you wrote this one, easy to understand and has a good flow.
One of basic patterns; Strategy pattern, encapsulate what varies (behaviors) and make them interchangeable at runtime, so that we can compose behaviors with a lot more flexibility.
@Fajar Endra Nusa indeed
it's one of the classic GoF pattern (-:
Thank you, best example of FCoI I've seen so far.