Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interfaces having only one implementation

When using jmock, you can mock a concrete class if you set the class imposteriser. I noticed that the class imposterizer is in the legacy package, so I really don't want to use it (especially because it super easy to extract an interface using the refactoring tools in my IDE). I don't like to have instance variables of concrete classes either.

Extracting the interface, however, I've noticed a pattern emerging in my code base. A lot of the time an interface has only one implementing concrete class. I prefer to use an interface wherever possible, but it seems really verbose to have all these extra files. Also, it's slightly tedious to update the interface and update the implementer every time I want to add a new method to the class.

Is this just the price you pay for proper abstraction or is there a better approach that I haven't thought of? Should all classes implement an interface even if the only thing in the interface is getters/setters?

like image 521
Dave Avatar asked Jul 30 '11 15:07

Dave


5 Answers

If the interface is only getters and setters, that sounds like it's more to do with data than behaviour - and doesn't sound like the sort of thing I'd mock. I'm happy to use simple production code directly within tests for other classes. I only inject dependencies for classes providing services.

I feel your pain, but personally I do still write the interface, even if there's currently only one production implementation. Quite often I'll find I write a stub or fake implementation as well after mocking for a while. Fakes can end up being rather simpler to use (leading to clearer tests) unless you're really interested in testing the interaction between the caller and the service.

It also means that when someone wants to look at methods a particular dependency provides, they can see just the interface with no implementation involved.

like image 168
Jon Skeet Avatar answered Oct 01 '22 21:10

Jon Skeet


Some general points I go by:

  • The mocks in your test are alternative implementations. So even if you only have one implementation in your product code, there will be more than one in the code base.
  • Prefer constructor injection to getters and setters. This will also make immutable objects more natural.
  • Interfaces describe the contract of a piece of behaviour, and does so in a way that the users of the interface need not know about the details of the implementation.
  • Don't make interfaces for things that aren't concerned with these things: abstracting away implementation details; multiple alternative implementations; mockability; behaviour.
  • Prefer designs that have many small composed parts, over designs that have few large interconnected parts.
  • If something is hard to test or mock, then try breaking it apart into smaller parts that have simpler APIs, and then compose those.
  • Give things precise names, and look out for duplication not only in code, but also in structure and names.
  • Avoid implementation inheritance - prefer composition instead. Interface inheritance is harder to misuse, and often falls out naturally when needed anyway.

These points will hopefully help you to make simpler and more testable and maintainable designs. At least after a bit of experience trying to follow them.

like image 31
Chris Vest Avatar answered Oct 01 '22 21:10

Chris Vest


If it's verbose and tedious it's bad style, no matter what the theoretical advantages are.

If it's easy to extract the interface using your tools why do it now? Why not do it when it actually has some real purpose. I see too much code that is architected with the future in mind instead of solving the problem at hand.

Of course all debate about these issues is just opinion. There are no facts to be found.

like image 45
jahhaj Avatar answered Sep 30 '22 21:09

jahhaj


You mention "proper abstraction". Well, it's only proper if the interface makes sense for more than one class. Especially considering that you are extracting the interfaces from concrete classes, you're probably ending up with methods in the interface which shouldn't be there. That is of course, if it makes sense for the interface itself to exists in the first place.

The last thing I'm going to point out is that your interfaces don't seem particularly stable. You seem to be implying that adding methods to interfaces is commonplace for you. I'd question the abstraction of class when the contract of the class (i.e. its interface) is so volatile.

All in all, I'm not convinced that immediately providing an interface for everything constitutes proper abstraction. Rather, waiting for the class's public interface to stabilize first, and then considering a proper abstraction (i.e. not just hitting the "extract interface..." button in IDE) is much better from a design perspective. Plus, a class might abstract into several unrelated interfaces, rather than a single interface.

like image 25
Ken Wayne VanderLinde Avatar answered Sep 27 '22 21:09

Ken Wayne VanderLinde


If your interface is primarily properties, it's likely that all the implementing classes are related, maybe an abstract class would be better suited for your needs. Then you can avoid some of the boilerplate. The primary functions of the abstract class could still be abstracted further by an interface.

interface IRunner {
      void run();
      int doOtherThing();
}

abstract class Thing implements IRunner {

    //this is class-specific
    abstract void run();
    //this is common to all 'Things'
    int doOtherThing() { return 0; }

    //as are these properties
    public int getProp() {...}
    public void setProp(int val) {...}

}

public class Goo extends Thing {
      public void run() {
         int i = getProp() + doOtherThing();
         makeMagicGoo(i);
      }

}
like image 34
scott Avatar answered Sep 30 '22 21:09

scott