11

Of late, I have been reading posts which talks about the supposed wrong notion that interfaces are abstractions. One such post is http://blog.ploeh.dk/2010/12/02/InterfacesAreNotAbstractions.aspx

I am a bit confused. If I don't have interfaces (interface/abstract class), then how will I inject my dependencies and mock them?

Also, I have heard people talk about not using interfaces which has just one implementor. Like this blog here - http://simpleprogrammer.com/2010/11/02/back-to-basics-what-is-an-interface/

Now all this, doesn't it violate the principle - Program to an interface and not implementation?

Sandbox
  • 7,910
  • 11
  • 53
  • 67
  • Related: https://stackoverflow.com/questions/2659366/java-interfaces-methodology-should-every-class-implement-an-interface – jaco0646 Oct 19 '18 at 19:56

5 Answers5

6

Programming to an interface instead of an implementation is more about using data abstraction and encapsulation.

When we say "interface" in terms of programming to an interface. That kind of interface means the external facing methods and properties of a class. It doesn't have to be a language level interface. (The keyword interface.)

You should be striving to make sure that your code is not dependent on the internal details of other classes.

John Sonmez
  • 7,128
  • 5
  • 37
  • 56
  • *When we say "interface" in terms of programming to an interface. That kind of interface means the external facing methods and properties of a class. It doesn't have to be a language level interface.* So, I have got it wrong all the while? So, a concrete class can be an interface according to you? – Sandbox Dec 09 '10 at 15:14
  • 5
    Correct. More specifically the public signatures of the methods and properties make up the interface of that class. Anytime you create a class whatever you choose to expose becomes part of that classes external interface. Changing it, breaks those that rely on it. If another class is relying on more than your interface, (they are relying on specific implementation details inside the class, for example how a list is sorted or data is stored), then even changing small internal things would break them. – John Sonmez Dec 09 '10 at 15:18
  • But when the code refers a concrete type, doesn't it mean that if we have another class tomorrow of similar type, we will have to change the code. Instead, with interfaces/abstract classses you can just swap out a different implementation at runtime. – Sandbox Dec 09 '10 at 15:25
  • 1
    You can still do that by subclassing concrete class. But, that is beside the point. If you don't need to swap out something for a different implementation, don't build the structure to do so. Doing so, creates extra complexity with no current value, only a hopeful future value. – John Sonmez Dec 09 '10 at 15:28
  • Subclassing creates its own complexities. So, I don't think subclassing a concrete class is actually a good solution. Leaving that apart, how do I know today that I will need a different implementation in future? I mean what is wrong in using an interface? – Sandbox Dec 09 '10 at 15:34
  • I don't suggest subclassing, it is generally bad. Interfaces create an extra level of indirection that doesn't add value unless you have multiple implementations of that interface. If you do that with every class you create, you end up creating a large amount of indirection in your project, which adds complexity. – John Sonmez Dec 09 '10 at 15:35
  • @John thanks for being patient with my queries. But, what do you mean when you say that it adds complexity. How does having multiple interfaces add complexity ?> – Sandbox Dec 09 '10 at 15:38
  • 1
    The most basic way it does is that you click on the source and go to the definition and find, oh it is an interface, then you have to check to see what actually implements that interface. Oh, just one class. Hmm, is that right? Am I missing something? Oh, no someone just added this interface so they could do dependency injection, it doesn't really serve a purpose. – John Sonmez Dec 09 '10 at 15:45
  • Well, it did serve the purpose of dependency injection and mocking. – Sandbox Dec 09 '10 at 15:46
  • 1
    Actually it only served the purpose of mocking, because unless you have more than one implementation, dependency injection didn't actually buy you anything, just added complexity. – John Sonmez Dec 09 '10 at 15:59
5

I'd say I disagree with many of the points in the linked articles:

  • interfaces are contracts. The contract has two parts - the method signature (purely syntactic) and the documentation.

  • interfaces are abstractions. I couldn't see an example of LSP violation. The IRectangle example is not a good one at all. The same thing can be said about Set extends Collection, where adding duplicates is disallowed. If you are passed a Collection you might be surprised it disallows duplicates. With the Collection interfaces this is taken care of by documenting that implementors may add restrictions

  • Leaky abstractions are inevitable. But this entirely depends on the designer. And btw "interfaces are leaky abstractions" means they are abstractions.

  • The guys seem to have missed "exposure" to unit-testing. Mock implementations are a very good reason to use an interface (although you can mock concrete classes as well).

  • A very good example from our current project - initially we has only one DAO implementation - one taking stuff form the database. But later we switched some of the operations to a dedicated search engine. We add another implementation of the DAO, and there we go. So having an interface with one implementation initially paid off.

  • Btw, initially SortedSet had only one implementation in the JDK - TreeSet. Now it has two. And many more from external libraries.

  • finally, interfaces (as a language construct) are a way to describe a class' functionality with the extra feature of disallowing any implementation slipping in. That is - interfaces are a hard to misuse way of providing abstraction.

That all said, you don't need an interface for everything. But it depends on the concrete case. I, for example, don't use interfaces for helper classes. And a valid point of the articles is the "programming to an interface" does not necessarily include the interface keyword. The "public interface" of a class is (theoretically) the set of its public methods.

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • 1
    Mock implementations are not a good reason to use an interface, they are a necessary evil, if you need a mock implementation. The problem is, our programming languages don't support the idea of providing mock implementations, so we abuse interface to achieve the result. While, I do it myself, I think it is still important to understand that it is wrong. We pay a price for extra interface, the price is complexity and lack of cohesion, because related things are no longer directly tied together in our code. – John Sonmez Dec 09 '10 at 15:49
  • as I said, mocks can be made on concrete classes as well (in Java at least, there are some powerful frameworks). However I don't think it is wrong to use mocks on interfaces. This is s different implementation of the same concept, right? The fact that it's used in a specific environment (unit-test) does not take anything from this - it's still an interface with 2 valid implementations. – Bozho Dec 09 '10 at 15:51
  • Also, you shouldn't use helper classes, they don't have a defined responsibility. They violate OO. – John Sonmez Dec 09 '10 at 15:52
  • they do have defined responsibility - to help ;) they reduce code duplication. – Bozho Dec 09 '10 at 15:56
  • 1
    I think you will have a tough time selling that one. – John Sonmez Dec 09 '10 at 15:57
  • as Martin Folwer once said "I'm no OO purist". Well, I'm neighter. But there are people that are ;) – Bozho Dec 09 '10 at 15:59
3

As long as you don't overdo it, I believe you're better off creating an interface.

Here's a use case I frequently have where having only one implementor is (in my opinion) perfectly fine: you have a Swing component, let's say it's a CarComparisonResultsPanel, which allows the user to see the results of the comparison between cars. As a user of the panel, I'd rather have a CarComparisonResult interface with just getCarSimilarities() and getCarDifferences() than a JPanel implementation that implements those methods as well as dozens of others.

EDIT: To make my "don't over do it" point a bit clearer, these are some examples of overdoing it: interfaces for Factories, Builders, Helper/Utility classes, GUI components that don't add relevant public methods to their parent, ...

espinchi
  • 9,144
  • 6
  • 58
  • 65
  • I would actually agree with you there. In that case you are using an interface in order to reduce complexity and visibility to the code using your CarComparisonResultsPanel. – John Sonmez Dec 09 '10 at 15:26
  • How does one decide about not overdoing it? I mean with with you client code referring interfaces/abstract classes you can always swap out an implementation at runtime. Also, if you don't have interfaces, how are you going to mock them? These two reasons, compels me to think that interfaces/abstract classes are perfectly valid in all cases. – Sandbox Dec 09 '10 at 15:29
  • I have a series of back to basics posts on my blog http://simpleprogrammer.com that goes into depth about interfaces and this exact topic, diving into DI and IoC etc, you might want to check that out. – John Sonmez Dec 09 '10 at 15:34
  • As you say, "not overdoing it" is very vague... but I guess putting it in words, without setting out scenarios with real code is just impossible (or at least beyond my explanation skills!) – espinchi Dec 09 '10 at 18:04
0

The principles behind programming to an interface don't have to be left to interface only situations. When you're designing your interfaces, the general questions you're asking are "Where am I expecting this to be consumed? By whom? And to what purpose?" Questions that should be asked even when creating implementation classes.

It might be that, while designing an interface, you come to the realization that you don't really need to make this an interface, and allowing overloading and inheriting will suffice for testing. As the first article mentioned, if you're consistently ending up with a 1:1 correlation between objects and interfaces with no purpose other than "I'm programming against interfaces," you're just making a mess of your code.

But, that doesn't mean you can't go ahead and design the class as if you were creating an interface/base class for it, with a set of generic methods/properties/fields that provide base functionality and then add other methods/properties/fields more specific to the implementation. Doing so would still, IMO, fall within the principles of programming to an interface. It would, also, certainly leave the door open for you to extract an interface/base class when a clear and definite need arose.

Wes P
  • 9,622
  • 14
  • 41
  • 48
  • I would say that allowing overloading and inheriting just for testing purpose is far, far worse than creating 1:1 interface. By inheritance you are introducing new complexity to your public API and opening a lot of possibilities to break the behavior of your class. 1:1 interface at least doesn't have such a side effects. – NOtherDev Dec 09 '10 at 15:52
0

You can have abstraction in two different flavors, which are:

  1. vertical ( “Is-a” relationship )
  2. horizontal ( methods )

When programmatically we decide for more generic types instead of more specific types, during the development phase, we bring abstraction to the code, because it doesn't matter at runtime which concrete implementation will be used (e.g. dependency injection, method declaration).

Along these lines, we use interfaces and abstract classes for greater generalization and loose coupling.

Another possibility would be by invoking a method, as the consuming application (client-side) would only use the functionality/service, being the implementation made within another class hidden from it.

enter image description here

Lucas de Lima
  • 51
  • 1
  • 3