Please consider using composition over inheritance when making design decisions.
Let’s quickly remind ourselves with composition and inheritance definitions:
Inheritance: I am something.
Example: employee is a person, apple is a fruit, and car is a vehicle.
Composition: I have something.
Example: employee has hands and feet, apple has skin and taste, car has wheels and engine.
Ok, let’s look at an example:
So we need to implement a software for a car.
And let’s make it simple our car can only turn and move.
Simple enough, we make the following class:
--------------------
class Car {
void turn() {
//turn car
}
void move()
//move car
}
}
--------------------
Good? Good. (People might immediately argue that we need to template or interface this object because it contains logic and is better practice to abstract any logics to the users, but we will use the XP way, simplest thing that works)
Now our program runs great for the car and everyone is happy...
But the requirement changed and we are now required to have software working for cars, trucks, suvs, vans etc.
Ok, not too bad, we can easily abstract one layer and implement it using:
------------------------------------------------------------------------------------------------------------------------------ interface vehicles / / / \ \ \ car truck van suv boat plane -------------------------------------------------------------------------------------------------------------------------------
In code we have:
-------------------
interface Vehicle {
void turn();
void move();
}
class Car implements Vehicle {
void turn() {
//turn car
}
void move(){
//move car
}
}
class Van implements Vehicle {
void turn() {
//turn van
}
void move(){
//move van
}
}
etc.
----------------------------------------------------------------------------------------------------------------------------
So far so good? Now what happens when we have a new vehicle called boatCar that turns like a boat and moves like a car?
With this architecture in place and time is on the run, what is the easiest thing to do?
We make a class like this:
--------------------------------
class BoatCar implements Vehicle {
void turn() {
//turn boat code
}
void move(){
//move car
}
}
---------------------------------
First sign of code duplication...
Now what if we need something turns like a car and moves like an suv?
Something turns like a boat, but moves like a van? Great...more code duplication with this design...
OR something worse, what if u have a car that can fly as well?
Then with inheritance it will become:
------------------------------------------------------------------------------------------------------------------------------ interface vehicle / / / \ \ \ car truck van suv boat plane / flyingCar -------------------------------------------------------------------------------------------------------------------------------
There are 2 ways to go about, create interface method for vehicle to fly?
Then we need to add void to all implementations for it.
OR we extend vehicle to flyingVehicle we have:
------------------------------------------------------------------------------- interface vehicle / \ inteface flyingVehicle car \ / flyingCar -------------------------------------------------------------------------------
class FlyingCar extends Car implements FlyingVehicle {
void turn() {
//turn car
}
void move(){
//move car
}
void fly(){
//fly car
}
}
---------------------------------
As things change, the structure of the software becomes so rigid and unmaintainable. And any new requirements will result in a high effort of refactoring.
But realistically, even the most experienced developer would end up in this kind of design when work is heavily loaded onto us.
When time is rushing we do whatever it takes to make things work.
That is why I am writing this article to ALWAYS remind ourselves to think composition rather than inheritance.
Now, let’s look at our solution if we used composition instead:
We need to implement different vehicles.
OK, what exactly are the vehicles consist of? How do we turn the car? Using steering wheel and wheels.
How do we move a car? Using engine, transmission, driveshaft and wheels.
For ease of understanding let’s keep it simple and assume we only need wheels to turn and engine to move:
--------------------------------------------------------
interface Wheel {
void turn();
}
interface Engine {
void move();
}
interface Vehicle {
void turn(Wheel wheel);
void move(Engine engine);
}
class VehicleImpl implements Vehicle {
void turn(Wheel wheel) {
wheel.turn();
}
void move(Engine engine){
engine.move();
}
/** OR
Wheel wheel = null;
setWheel(Wheel wheel){...}
Engine engine = null;
setEngine(Engine engine){...}
void turn() {
this.wheel.turn();
}
void move(){
this.engine.move();
}
*/
}
-----------------------------------------------------------
With the above design, when we need a vehicle that turns like a boat and moves like a car we do:
----------------------------------------------------------
class BoatWheel implements Wheel {...}
class CarEngine implements Engine {...}
Wheel boatWheel = new BoatWheel();
Engine carEngine = new CarEngine();
Vehicle boatCar = new VehicleImpl();
//to turn
boatCar.turn(boatWheel);
//to move
boatCar.move(carEngine);
/** 2nd design case
boatCar.setWheel(boatWheel);
boatCar.setEngine(carEngine);
//to turn
boatCar.turn();
//to move
boatCar.move();
*/
-------------------------------------------------------------
Simple and easy to implement. And any new features or requirements developers will simple make new engines and wheels to accommodate them.
Please excuse me for the imperfect designs. But the point of this article is to remind ourselves to think like:
Apple HAS skin and flesh rather than apple IS a fruit.
And is New Year of 2010!! Happy New Years Everyone.
I will go out and socialize abit as well!