Monday, 5 March 2012

Interface vs Abstract class. The classic confusion

One of the mostly asked question in OOP is about choosing between an Interface and an Abstract class.  These two look pretty similar and it appears as if one could be used instead of another. So, which one should be most appropriate to use to lay out class designs?

These two things are similar, and both talk about abstraction, rather than concrete implementation. Both concepts are interpreted and inherited from the real world. But, there is a small difference in their purpose.

Interface talks about "What" functionality a particular kind of object should have, and, it doesn't care about exactly "How" these functionality should be implemented by the actual objects of those kind.

For example, let us consider a Vehicle object. A vehicle could be of any brand in the world. But, what are the core functionality of a vehicle? What would you expect from a vehicle while you try to purchase one? The very basic things you would expect would be:

It must start
It must run
It must break
It must accelerate
It must stop

So, how would you identify these "very basic" features for any vehicle in the OOP?

You already know it. You create an interface and put these functionality as some method signatures without definition. That is:

interface IVehicle
{
     void Start();
     void Run();
     void Accelerate();
     void Break();
     void Stop();
}

So, this basically describes what are the basic functionality that a vehicle (Any vehicle made by any manufacturer) should have. Now, how these functionality are going to be implemented? Well, It completely depends on the manufacturers. One particular kind of vehicle might start using a Remote control, and another might start with a Key. One might accelerate via an auto gear and another might accelerate via a manual gear. In OOP, these particular implementations are defined by the classes which implements the interface. The interface knows nothing about these concrete implementation and it is quite happy about that.

On the other hand, an "Abstract class" also talks about "What" functionality a particular kind of object should have, but, it may also talk about "How" a particular functionality is implemented.

Need an example? Here you go

Toyota makes cars and of course all of its cars have the very basic functionality that a vehicle should have. So, each car obviously implements the IVehicle interface. For now, let us assume Toyota makes cars based upon only two models, the Camry and the XCorolla. So, while laying out the Camry and XCorolla classes, they implement the IVehicle classes as follows:

class Camry : IVehicle
{
    public void Start()
    {
         //Starts with a Remote control
    }

    public void Run()
    {
         //Runs via a 2000CC Toyota engine
    }

    public void Accelerate()
    {
         //Accelerates via an Auto gear
    }

    public void Break()
    {
         //Breaks via an hydrolic break
    }

    public void Stop()
    {
         //Stops with a key, or a remote control
    }
}

class XCorolla: IVehicle
{
    public void Start()
    {
         //Starts with a Key

    }

    public void Run()
    {
         //Runs via a 1500CC Toyota engine

    }

    public void Accelerate()
    {
         //Accelerates via an Auto gear

    }

    public void Break()
    {
         //Breaks via an hydrolic break

    }

    public void Stop()
    {
         //Stops with a key

    }

}


Looks pretty good, but, wait a minute. The Camry and the XCorolla class both seem to be having a same implementation for Accelerate() and Break(), though, these two classes implement the other three functionality Start(), Run() and Stop() in different ways. So, as these two classes have a same implementation for the Accelerate() and Break() functionality, why shouldn't these be re-used?


The IVehicle interface could of-course be used in this case, but, it is not allowing to re-use the same functionality Accelerate() and Break(). So, how about using an Abstract class?

Let us help Toyota to improve their programs a bit, by creating an abstract class Car, that contains the common functional implementation for Accelerate and Break.

abstract class Car : IVehicle
{
    public abstract void Start();
    public abstract void Run();
    public abstract void Stop();
    
    public void Accelerate()
    {
         //Accelerates via an Auto gear
    }
    public void Break()
    {
         //Breaks via an hydrolic break
    }
}

As you see, the abstract class Car contains concrete implementations of Accelerate() and Break() function (They have method definition), but, abstract implementation of Start(), Run() and Stop() (They don't have method definition). Why two concrete implementations? Because, these two functions are the same for both Camry and the XCorolla classes. Why two abstract implementations? Because, these two function's concrete implementation are not same for Camry and XCorolla classes.

So now, the Camry and the XCorolla classes would be re-defined as follows:

class Camry : Car
{
     public void Start()
    {
         //Starts with a Remote control
    }
     public void Run()
    {
         //Runs via a 2000CC Toyota engine
    }
    public void Stop()
    {
         //Stops with a key, or a remote control
    }
}

class XCorolla: Car
{
     public void Start()
    {
         //Starts with a Key

    }
     public void Run()
    {
         //Runs via a 1500CC Toyota engine

    }
    public void Stop()
    {
         //Stops with a key

    }
}

This time, the Camry and the XCorolla classes don't include the definition of  Break() and Accelerate(), because, they inherit those from the abstract Car class.

To summarize, the purpose of abstract classes is not only to define abstraction between classes, but also to define concrete definition of functions which are common across the concrete implementation classes. Interfaces allow us to identify (Not implement) the functionality a particular kind of object where Abstract classes allows to both identify and implement the functionality across the objects, that increases re-usability and code manageability and allows to build better systems.

However, it doesn't mean that, all interfaces should be replaced with Abstract classes. Try to use Abstract classes wherever possible and wherever applicable, where use of Abstract classes allows you to increase code manageability and reuse.


Enjoy abstraction.

Post a Comment