3

I've read these questions:

I don't understand how to "program to an interface" if you are using methods in concrete classes that aren't part of the interface.

I realize the most common example of this design principle is the List vs ArrayList in Java because it is easy to understand and illustrate the point.

Here is a somewhat silly example to illustrate what my question is asking (the code is in PHP but it applies to most OOP languages):

interface ResponseInterface {
    public function getStatusCode();
}

class Response implements ResponseInterface {
    private $status;

    public function getStatusCode() {
        return $this->status;
    }
}

class AwesomeResponse implements ResponseInterface {
    private $status;
    private $message = ['200' => 'OK', '500' => 'Internal Server Error'];

    public function getStatusCode() {
        return $this->status;
    }

    public function getStatusMessage() {
        return $this->message[$status];
    }
}

class Server {
    public function sendResponse(ResponseInterface $response) {
        // this seems wrong -----^

        header(vsprintf('HTTP/1.1 %d %s', [
            $response->getStatusCode(),
            $response->getStatusMessage()
        ]), true, $response->getStatusCode());
    }
}

As you can see, the sendResponse method takes a ResponseInterface parameter but it calls getStatusMessage() which isn't part of the interface but only something implemented in AwesomeResponse, which implements ResponseInterface.

The application crashes at runtime when a Response object is passed as it tries to call the non-existent method getStatusMessage(). Therefore, the proper implementation would be:

public function sendResponse(AwesomeResponse $response) {
    // ...stuff
}

But AwesomeResponse isn't an interface so how do I program to an interface?

  • 2
    Quick answer: you cannot always program to an interface if you rely on implementation details such as this. Java should ideally have a RandomAccessList interface that is a subinterface of List and RandomAccess and contains signatures of the methods on ArrayList that are not on any interface. – user22815 Dec 12 '15 at 3:30
  • 3
    Well if you're programming to the interface ResponseInterface, and ResponseInterface has no status messages, then there is no such thing as a status message as far as you are concerned. – immibis Dec 12 '15 at 11:54
  • 2
    (So your options are to add getStatusMessage to ResponseInterface, or to stop pretending that your code works with any object that implements ResponseInterface (i.e. stop "programming to that interface")) – immibis Dec 12 '15 at 11:55
  • If you want to follow this principle religiously, your IDE should make it painless. IntelliJ-IDEA supports "extract interface" refactoring which also finds and replaces occurrences of concrete variables with their corresponding interface declaration. Also, I'm sure you can find an analyzer in IntelliJ which will automatically find all non-library places where you declare concrete variables. – michaelsnowden Dec 13 '15 at 23:57
5

Hmm - a less trivial example might help. Consider Executor, which is an interface that defines a contract for executing Runnables.

Now, if you write AwesomeService like this:

class AwesomeService {
    // ...
    public void runAllPendingTasks(ScheduledThreadPoolExecutor executor) {
        for(Runnable task : pendingTasks) {
            executor.execute(task);
        }
    }
 }

Then my code, trying to call yours, needs to find a ScheduledThreadPoolExecutor lying around somewhere. On the other hand, if your method signature admits that your needs can be satisfied by anything that implements Executor

class AwesomeService {
    // ...
    public void runAllPendingTasks(Executor executor) {
        for(Runnable task : pendingTasks) {
            executor.execute(task);
        }
    }
 }

The my code can pass you my customized Executor, and there by enhance what actually happens when you run your tasks. For instance, I might want to track how often we run tasks, so that I can generate metrics in real time that monitor the health of the application.

class MeteredExecutor implements Executor {
    private final Executor impl;
    private final io.dropwizard.metrics.Meter meter;

    MeteredExecutor(...) {...}

    public void execute(Runnable command) {
        meter.mark();
        impl.execute(command);
    }
}

OK, so why doesn't an interface seem to help for AwesomeResponse? The primary answer is encapsulation -- the MeteredExecutor provides the execute service by using its own internal state to satisfy a request. What it doesn't do is share that internal state. Notice that AwesomeService calls execute, and lets the MeteredExecutor do the work, rather than calling getMeter().mark() and getImpl.execute(command).

"Give me your internal state" is a really lousy motivation for an interface.

AwesomeResponse is exposing its data. That's not necessarily a bad thing; in your example as written, AwesomeResponse is essentially a representation of a message that is about to cross an application boundary. Put another way, it's a value type that makes up part of the api of your Service; of course it exposes its data, that's what it is for!

Calling out the same point a different way: notice that in the case of AwesomeService and the interfaces, state is being passed inwards. My state is an executor, and I pass that to AwesomeService. The state of AwesomeService is a task, an it passes that task to the Executor, which in turn passes it inward to another Executor, and turtles all the way down. Interfaces work great for this.

On the other hand, in AwesomeResponse, the state is coming out. Writing interfaces to fetch the state out is just extra work.

BUT

Encapsulation is a good thing, and AwesomeResponse isn't quite at the application boundary. Could we rewrite things so that state is passed inward?

interface Writer {
    void header(int code, String message);
}

interface Response {
    void writeTo(Writer writer);
}

class AwesomeResponse implements Response {
    void writeTo(Writer writer) {
        writer.header(this.code, this.message);
    }
}

class NotSoAwesomeResponse implements Response {
    void writeTo(Writer writer) {
        writer.header(this.code, String.valueOf(this.code));
    }
}

class ServerWriter implements Writer {
    void header(int code, String message) {
        header(vsprintf('HTTP/1.1 %d %s', [
            code,
            message
        ]), true, code);
    }
}

class Server {
    public function sendResponse(Response response) {
        ServerWriter writer = new ServerWriter();
        response.writeTo(writer);
    }
}
  • I think there might be some typos and missing instance fields in this code example.... – Nathan Tuggy Dec 13 '15 at 0:03
8

That is the point. If you depend on concrete details of the class, you are not coding to an interface by definition.

This means you cannot drop out those implementation details and replace them with others. Since change is inevitable in business, this is going to cause you problems down the road. You will need to add that capability to the interface (or make another interface for that other functionality) and work with that contract, not the details that you happen to be using now.

2

First of all: this has nothing to do with interfaces which are defined by the keyword of the same name.

The advice means nothing else than not to rely on a concrete implementation, rather on a well defined abstract behaviour.

My knowlede of PHP is near 0 - so I apologize answering in a more general way.

Say you have an e-commerce application and domain-objects like order. Every order was created on some point in time. Oftentimes there are filteringoperations to get a subset of orders within a given timeframe. You could write conditions like order.getCreated() > concreteDate. Besides other code smells, this is bad for another reason: You tie your code to the implementation fact, that the > operation works with your code. If the implementation of the date is ever changed - say you use another Date object with other operators (e.g. .after()), your code is broken.

If you designed the order in a proper way, you would define the operation as order.createdAfter(date), you define an interface aka. a well defined way to get information you need from an order, which is itself independed from the concrete implementation. The input is a Date and the result is a boolean.

It is allways good practice to choose the most abstract datatype for returnvalues to prevent assumptions (= dependencies) on concrete implementations. For example, it would be good practice in Java to return Iterable<T> instead of concrete List to prevent assuptions about the behaviour of the resulting collection.

tl;dr

Read interface as well defined behaviour independent from concrete implementations.

  • 3
    Yes! Thinking that a Java interface is meant when talking about "programming to interfaces" is just wrong. – Deduplicator Dec 12 '15 at 17:35
  • UP. createdAfter(date) - on its face is excellent - Alan Kay would give it a thumbs up. But that's about why we encapsulate, vice polymorphism. OTOH Iterable<T> is quite to point. Kay would say "it's all about the message". i.e. if there is a matching-signature method then the call (message) will be handled, period. He regrets coining object oriented programming because object type gets emphasis and strong typing restricts flexibility. SmallTalk, LISP, JavaScript, etc. coders look at us with pity. – radarbob Dec 15 '15 at 20:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.