What does "program to interfaces, not implementations" mean?

70,277

Solution 1

Interfaces are just contracts or signatures and they don't know anything about implementations.

Coding against interface means, the client code always holds an Interface object which is supplied by a factory. Any instance returned by the factory would be of type Interface which any factory candidate class must have implemented. This way the client program is not worried about implementation and the interface signature determines what all operations can be done. This can be used to change the behavior of a program at run-time. It also helps you to write far better programs from the maintenance point of view.

Here's a basic example for you.

public enum Language
{
    English, German, Spanish
}

public class SpeakerFactory
{
    public static ISpeaker CreateSpeaker(Language language)
    {
        switch (language)
        {
            case Language.English:
                return new EnglishSpeaker();
            case Language.German:
                return new GermanSpeaker();
            case Language.Spanish:
                return new SpanishSpeaker();
            default:
                throw new ApplicationException("No speaker can speak such language");
        }
    }
}

[STAThread]
static void Main()
{
    //This is your client code.
    ISpeaker speaker = SpeakerFactory.CreateSpeaker(Language.English);
    speaker.Speak();
    Console.ReadLine();
}

public interface ISpeaker
{
    void Speak();
}

public class EnglishSpeaker : ISpeaker
{
    public EnglishSpeaker() { }

    #region ISpeaker Members

    public void Speak()
    {
        Console.WriteLine("I speak English.");
    }

    #endregion
}

public class GermanSpeaker : ISpeaker
{
    public GermanSpeaker() { }

    #region ISpeaker Members

    public void Speak()
    {
        Console.WriteLine("I speak German.");
    }

    #endregion
}

public class SpanishSpeaker : ISpeaker
{
    public SpanishSpeaker() { }

    #region ISpeaker Members

    public void Speak()
    {
        Console.WriteLine("I speak Spanish.");
    }

    #endregion
}

alt text

This is just a basic example and actual explanation of the principle is beyond the scope of this answer.

EDIT

I have updated the example above and added an abstract Speaker base class. In this update, I added a feature to all Speakers to "SayHello". All speaker speak "Hello World". So that's a common feature with similar function. Refer to the class diagram and you'll find that Speaker abstract class implement ISpeaker interface and marks the Speak() as abstract which means that the each Speaker implementation is responsible for implementing the Speak() method since it varies from Speaker to Speaker. But all speaker say "Hello" unanimously. So in the abstract Speaker class we define a method that says "Hello World" and each Speaker implementation will derive the SayHello() method.

Consider a case where SpanishSpeaker cannot Say Hello so in that case you can override the SayHello() method for Spanish Speaker and raise proper exception.

Please note that, we have not made any changes to Interface ISpeaker. And the client code and SpeakerFactory also remain unaffected unchanged. And this is what we achieve by Programming-to-Interface.

And we could achieve this behavior by simply adding a base abstract class Speaker and some minor modification in Each implementation thus leaving the original program unchanged. This is a desired feature of any application and it makes your application easily maintainable.

public enum Language
{
    English, German, Spanish
}

public class SpeakerFactory
{
    public static ISpeaker CreateSpeaker(Language language)
    {
        switch (language)
        {
            case Language.English:
                return new EnglishSpeaker();
            case Language.German:
                return new GermanSpeaker();
            case Language.Spanish:
                return new SpanishSpeaker();
            default:
                throw new ApplicationException("No speaker can speak such language");
        }
    }
}

class Program
{
    [STAThread]
    static void Main()
    {
        //This is your client code.
        ISpeaker speaker = SpeakerFactory.CreateSpeaker(Language.English);
        speaker.Speak();
        Console.ReadLine();
    }
}

public interface ISpeaker
{
    void Speak();
}

public abstract class Speaker : ISpeaker
{

    #region ISpeaker Members

    public abstract void Speak();

    public virtual void SayHello()
    {
        Console.WriteLine("Hello world.");
    }

    #endregion
}

public class EnglishSpeaker : Speaker
{
    public EnglishSpeaker() { }

    #region ISpeaker Members

    public override void Speak()
    {
        this.SayHello();
        Console.WriteLine("I speak English.");
    }

    #endregion
}

public class GermanSpeaker : Speaker
{
    public GermanSpeaker() { }

    #region ISpeaker Members

    public override void Speak()
    {
        Console.WriteLine("I speak German.");
        this.SayHello();
    }

    #endregion
}

public class SpanishSpeaker : Speaker
{
    public SpanishSpeaker() { }

    #region ISpeaker Members

    public override void Speak()
    {
        Console.WriteLine("I speak Spanish.");
    }

    public override void SayHello()
    {
        throw new ApplicationException("I cannot say Hello World.");
    }

    #endregion
}

alt text

Solution 2

Think of an interface as a contract between an object and its clients. That is the interface specifies the things that an object can do, and the signatures for accessing those things.

Implementations are the actual behaviours. Say for example you have a method sort(). You can implement QuickSort or MergeSort. That should not matter to the client code calling sort as long as the interface does not change.

Libraries like the Java API and the .NET Framework make heavy use of interfaces because millions of programmers use the objects provided. The creators of these libraries have to be very careful that they do not change the interface to the classes in these libraries because it will affect all programmers using the library. On the other hand they can change the implementation as much as they like.

If, as a programmer, you code against the implementation then as soon as it changes your code stops working. So think of the benefits of the interface this way:

  1. it hides the things you do not need to know making the object simpler to use.
  2. it provides the contract of how the object will behave so you can depend on that

Solution 3

It means that you should try to write your code so it uses an abstraction (abstract class or interface) instead of the implementation directly.

Normally the implementation is injected into your code through the constructor or a method call. So, your code knows about the interface or abstract class and can call anything that is defined on this contract. As an actual object (implementation of the interface/abstract class) is used, the calls are operating on the object.

This is a subset of the Liskov Substitution Principle (LSP), the L of the SOLID principles.

An example in .NET would be to code with IList instead of List or Dictionary, so you could use any class that implements IList interchangeably in your code:

// myList can be _any_ object that implements IList
public int GetListCount(IList myList)
{
    // Do anything that IList supports
    return myList.Count();
}

Another example from the Base Class Library (BCL) is the ProviderBase abstract class - this provides some infrastructure, and as importantly means all provider implementations can be used interchangeably if you code against it.

Solution 4

If you were to write a Car Class in Combustion-Car era, then there is a great chance you would implement oilChange() as a part of this Class. But, when electric cars are introduced, you would be in trouble as there is no oil-change involved for these cars, and no implemention.

The solution to the problem is to have a performMaintenance() Interface in Car class and hide details inside appropriate implementation. Each Car type would provide its own implementation for performMaintenance(). As a owner of a Car all you have to deal with is performMaintenance() and not worry about adapting when there is a CHANGE.

class MaintenanceSpecialist {
    public:
        virtual int performMaintenance() = 0;
};

class CombustionEnginedMaintenance : public MaintenanceSpecialist {
    int performMaintenance() { 
        printf("combustionEnginedMaintenance: We specialize in maintenance of Combustion engines \n");
        return 0;
    }
};

class ElectricMaintenance : public MaintenanceSpecialist {
    int performMaintenance() {
        printf("electricMaintenance: We specialize in maintenance of Electric Cars \n");
        return 0;
    }
};

class Car {
    public:
        MaintenanceSpecialist *mSpecialist;
        virtual int maintenance() {
            printf("Just wash the car \n");
            return 0;
        };
};

class GasolineCar : public Car {
    public: 
        GasolineCar() {
        mSpecialist = new CombustionEnginedMaintenance();
        }
        int maintenance() {
        mSpecialist->performMaintenance();
        return 0;
        }
};

class ElectricCar : public Car {
    public: 
        ElectricCar() {
             mSpecialist = new ElectricMaintenance();
        }

        int maintenance(){
            mSpecialist->performMaintenance();
            return 0;
        }
};

int _tmain(int argc, _TCHAR* argv[]) {

    Car *myCar; 

    myCar = new GasolineCar();
    myCar->maintenance(); /* I dont know what is involved in maintenance. But, I do know the maintenance has to be performed */


    myCar = new ElectricCar(); 
    myCar->maintenance(); 

    return 0;
}

Additional explanation: You are a car owner who owns multiple cars. You carve out the service that you want to outsource. In our case we want to outsource the maintenance work of all cars.

  1. You identify the contract(Interface) that holds good for all your cars and service providers.
  2. Service providers come out with a mechanism to provide the service.
  3. You don't want to worry about associating the car type with the service provider. You just specify when you want to schedule maintenance and invoke it. Appropriate service company should jump in and perform the maintenance work.

    Alternate approach.

  4. You identify the work(can be a new interface Interface) that holds good for all your cars.
  5. You come out with a mechanism to provide the service. Basically you are going to provide the implementation.
  6. You invoke the work and do it yourself. Here you are going to do the job of appropriate maintenance work.

    What is the downside of the 2nd approach? You may not be the expert at finding the best way to do the maintenance. Your job is to drive the car and enjoy it. Not to be in the business of maintaining it.

    What it the downside of the first approach? There is the overhead of finding a company etc. Unless you are a rental car company, it may not be worth the effort.

Solution 5

This statement is about coupling. One potential reason for using object oriented programming is reuse. So for example you can split your algorithm among two collaborating objects A and B. This might be useful for later creation of another algorithm, which might reuse one or another of the two objects. However, when those objects communicate (send messages - call methods), they create dependencies among each other. But if you want to use one without the other, you need to specify what should do some other object C do for object A if we replace B. Those descriptions are called interfaces. This allows object A to communicate without change with different object relying on the interface. The statement you mentioned says that if you plan to reuse some part of an algorithm (or more generally a program), you should create interfaces and rely on them, so you might change the concrete implementation any time without changing other objects if you use the declared interface.

Share:
70,277

Related videos on Youtube

never_had_a_name
Author by

never_had_a_name

Updated on December 28, 2020

Comments

  • never_had_a_name
    never_had_a_name over 3 years

    One stumbles upon this phrase when reading about design patterns.

    But I don't understand it, could someone explain this for me?

  • never_had_a_name
    never_had_a_name about 14 years
    but how can a client interact with an interface and use its empty methods?
  • Gabriel Ščerbák
    Gabriel Ščerbák about 14 years
    Client does not interact with the interface, but through the interface:) Objects interact with other objects through methods (messages) and an interface is a sort of a language - when you know that certain object (person) implements (speaks) english (IList), you can use it withouth any need to know more about that object (that he is also an Italian), because it is no needed in that context (if you want to ask for help you do not need to know he speaks also Italian if you understand English).
  • Gabriel Ščerbák
    Gabriel Ščerbák about 14 years
    BTW. IMHO Liskov substitution principle is about semantic of inheritance and has nothing to do with interfaces, which can be found also in languages without inheritance (Go from Google).
  • Joachim Sauer
    Joachim Sauer about 14 years
    Programming to the interface is not only about the type of the reference variable. It also means that you don't use any implicit assumptions about your implementation. For example if you use a List as the type, your still could still be assuming that random access is fast by repeatedly calling get(i).
  • penguat
    penguat about 14 years
    It does mean you need to be aware of what you are contracting the object to do: in the example provided you are only contracting for a sort, not necessarily a stable sort.
  • T .
    T . about 14 years
    Factories are orthogonal to programming to interfaces, but I think this explanation makes it seem as though they're part of it.
  • this. __curious_geek
    this. __curious_geek about 14 years
    @Toon: agree with you. I wanted to provide a very basic and simple example for programming-to-interface. I didn't want to confuse the questioner by implementing IFlyable interface on few birds' and animals' classes.
  • never_had_a_name
    never_had_a_name about 14 years
    @this. if i instead use an abstract class or a facade pattern, will it still be called "program to an interface"? or do i explicitly have to use an interface and implement it on a class?
  • this. __curious_geek
    this. __curious_geek about 14 years
    No. using abstract class would be a different scenario as compared to "program-to-interface". In this case you'd have your abstract class implement an interface and let other classes be inherited from the abstract class which will also make them inherit the Interface as well. Will update my examples for your reference soon.
  • this. __curious_geek
    this. __curious_geek about 14 years
    @ajsie: Updated the answer with modified example and class-diagram. Hope this helps.
  • appbootup
    appbootup over 11 years
    One of the image url is broken :(
  • Adam Arold
    Adam Arold about 11 years
    What uml tool were you using to create the images?
  • Rogério
    Rogério almost 10 years
    "... the client code always holds an Interface object which is supplied by a factory". No, this is incorrect. It's not what the principle is about. If you write List aList = new ArrayList(), you are coding to the List interface, not to the ArrayList implementation (using Java here). Even more, if you use a class with no separate interface, such as StringBuilder bldr = new StringBuilder() (which implements the CharSequence interface, but we can ignore that here) you are still coding to an interface, not an implementation (the implicit public interface of class StringBuilder).
  • Joe Iddon
    Joe Iddon over 5 years
    So similar to how library documentation doesn't mention implementation, they are just descriptions of included class interfaces.
  • miatech
    miatech over 4 years
    ok, why having an abstract class and an interface. you could've had just an abstract class and have subclasses extend that class. The first implementation makes more sense to me an interface and the 3 sub-classes, which if I'm not mistaken is Factory-Pattern.