Teaser Image

qnoid

Markos Charatzas - London, UK




/**
 * Pity me
 */
public class Driver
{
    public void drive(Porsche porsche)
    {
        porsche.drive();
    }
}

/**
 * Had to learn how to drive a Yugo after the crisis hit me
 */
public class Driver
{    
    public void drive(Porsche porsche)
    {
        porsche.drive();
    }
    
    public void drive(Yugo yugo)
    {
        yugo.drive();
    }
}

/**
 * Gas for all!
 */
public class Driver
{
    public void drive(GasolineCar gasolineCar)
    {
        gasolineCar.drive();
    }    
}

/**
 * Not again....
 *
 */
public class Driver
{
    public void drive(ElectricalCar electricalCar)
    {
        electricalCar.drive();
    }
    
    public void drive(GasolineCar gasolineCar)
    {
        gasolineCar.drive();
    }
}

/**
 * "I'm the King of the world"
 */
public class Driver
{
    public void drive(Car car)
    {
        car.drive();
    }    
}

/**
 * All I wan't to do is drive...
 */
public interface Car
{
    public void drive();
}

/**
 * Nitro baby!
 */
public class NitroCar implements Car
{
    private final Car car;    
    
    public NitroCar(Car car)
    {
        this.car = car;
    }

    private void applyNitro()
    {
        System.out.println("Applying Nitrous Oxide");
    }

    @Override
    public void drive()
    {
        this.applyNitro();
        this.car.drive();
    }
}

/**
 * Let's put this nitro to the test
 */
public class DriverTest
{
    @Test
    public void drive() throws Exception
    {
        Driver brianOConner = new Driver();
        
        Car eclipse = new MitsubishiEclipseRS();
        Car nitroCar = new NitroCar(eclipse);
        
        /*
         * "O'Conner appears to be ahead in the race, having equipped his Eclipse with Nitrous Oxide" (as quoted by Wikipedia The Fast and the Furious (2001 film)
 article)
         */
        brianOConner.drive( nitroCar );
    }
}

What if your driver's licence said you can only drive a Porsche?

The money crisis is on and you have to sell your precious little horse for a new Yugo Zastava[Disclaimer]. You have to learn how to drive that as well.

In OO terms you are now presented with two options.

  • Add another method that allows you to drive the Yugo.
  • Extract an abstract class that allows you to drive any car

Now ask yourself this. How "abstract" will that abstract class be? Will you go as far as to define an AbstractCar class? What methods will this class define and how usefull will inheritance prove to be after all? Will you define an abstract GasolineCar that will at least give you some basic implementation on how such a car operates when you drive it?

So you go on and just use an abstract GasolineCar class since all cars run on gas anyway.

The electrical revolution is upon us and all of a sudden both your Porsche and Yugo are overshadowed by Toyota. Yet, you are left with driving just GasolineCar(s).

Now again you have two options.

  • Add another method that allows you to drive the ElectricCar
  • Extract an abstract class that allows you to drive any car

See a pattern here? It ain't fun driving any more.

You give up and introduce an AbstractCar class after all to decouple the Driver from any implementation, but ask yourself this (rather rhetorical) question. If that abstract class merely defines an abstract drive method (or even a set of abstract methods) and nothing more, isn't that what an interface is all about?

In this example obviously there is a need to drive different (implementations of) cars. You shouldn't neccesary have to create an interface for every implementation that you have but use your best judgement and reasoning on where it's suitable to do so. When designing an API will make more sense as you see a reason to make it extensible. In any case structure your code in such a way that when presented with the task you can easily introduce an interface later.

Most likely you will be introducing an abstract class to encapsulate a common algorithm for all your inheriting classes but tightening yourself to an abstract class is tightening yourself to an implementation which isn't that obvious at first sight.

Think of an interface as a way to describe behaviour for your classes without any sort of definition of how the methods relate together. e.g. what can you do with all the cars? Drive them!

As a bonus to coding to an interface you can easily extend your cars (even at runtime!) by using composition over inheritance. All of a sudden you are fast and furious.

The above isn't by any means a play of Greek tragedy in some theater in Epidaurus. Though an example it is very much real.

Disclaimer: No disrespect for the Yugo Zastava