Concrete Class Dependency

Symptoms

A class depends on other concrete classes. In order to favour decoupling (and thereby testability) we recommend depending on interfaces instead.

public class A {
    private final B b;

    public A(B b) {
        this.b = b;
    }
}

public class B {
}

Causes

Laziness

What to do

In order to reduce A's tight coupling, split B in an Interface Implementation Separation.

public interface B {
}

public class BImpl implements B {
}

Labels

 
(None)
  1. Mar 03, 2004

    steve_molitor says:

    Just to play devils' advocate: How does refactoring like this improve decoupling...

    Just to play devils' advocate:

    How does refactoring like this improve decoupling and testability? The advantage of an interface is abstraction. But if an interface only has one implementation, and there's a one to one mapping between the interface and implementation public methods, there's no abstraction. Just extra maintenance to keep the interface and implementation declarations in sync. According to Larry Wall, laziness is one of the three great virtues of a programmer. Enlightened laziness encourages maintainability.

    You could change B into an interface at any time, without disturbing A. Class A is still programming to the interface (interface in the OO sense) of B in either case. I would argue the example above is a YAGNI violation.

  2. Mar 03, 2004

    Aslak Hellesøy says:

    Stephen, Letting a class A depend on an interface B rather than a class B improv...

    Stephen,

    Letting a class A depend on an interface B rather than a class B improves testability because it will allow you to provide A with a dynamic mock implementation of B in unit tests that tests A. (Mock frameworks generally allow you to mock interfaces, but not concrete classes).

    Ideally you would always have at least two implementations of an interface: The one(s) that you use in the assembled system and the one(s) you use when testing the class.

  3. Mar 04, 2004

    steve_molitor says:

    Aslak, Thanks for the reply. The testing issue depends on the technical details ...

    Aslak,

    Thanks for the reply. The testing issue depends on the technical details of the mock framework you are using. We have a hacked version of MockObjects that uses CGLIB to allow mocking of concrete classes. So always creating interfaces for classes might not be a general best practice, but just a kludge required for certain testing frameworks. I expect that over time, most Java testing frameworks will support mocking of concrete classes.

    I find systems that have an interface for every class a bit hard to follow. Almost every class depends on another class (even if it's just a JDK class). So creating interfaces for everything could get a bit crazy.

    But I would argue that in the first part of the example above, class A does not depend on a concrete class. Class A does not know whether B is a concrete class or an interface. You could change B from a concrete class to an interface later, and A would never know. Ergo, A does not depend on a concrete class. It just depends on something named 'B', with a certain set of methods. I.e., it depends on a logical 'interface'. The mechanics of how the rest of the system supplies an implementation of that interface are of no concern to class A. It doesn't matter if the rest of the system satisifies 'A' by creating a concrete class B, or using an interface/impl pair. Ergo, 'A' does not depend on the existence of a concrete class 'B'. There is no concrete class dependecy. I agree that dependencies on concrete classes are bad, but I don't think the example contains a concrete class dependency.

    I think part of this come from confusion over the meaning of the phrase 'programming to an interface.' The concept of an 'interface' predates Java's interface construct. An OO 'interface' is simply a named set of method signatures, with specified semantics. Depending on a particular implementation would mean taking advantage of unintentional side effects of a particular implemention, instantiating an implementation directly, etc. As long as implementations can be substituted without disturbing clients, then clients are not dependent on concrete implementations. The mechanism for declaring the 'interface', whether literally a Java interface, an abstract class, a concrete class, or whatever, is less important.

    Now, if 'A' instantiated 'B' directly, by calling 'new B()', then yes, you'd have a dependency on a concrete class. And that's where Pico comes in!

  4. Mar 04, 2004

    Aslak Hellesøy says:

    Stephen, You are making some valid points :) Ironically, I have contributed a pl...

    Stephen,

    You are making some valid points

    Ironically, I have contributed a plugin for JMock (http://jmock.codehaus.org/) that supports mocking of concrete classes with CGLIB too (JMock is the successor of MockObjects - by the original authors of MockObjects).

    I didn't mention it in my previous post, because I still believe that interfaces are better for decoupling. However, I realise this is a matter of taste. We picodevelopers are anal purists, that's all

  5. Mar 04, 2004

    steve_molitor says:

    Hey Alsak, I use interfaces a lot for decoupling too, just not everywhere. Some...

    Hey Alsak,

    I use interfaces a lot for decoupling too, just not everywhere. Sometimes it seems like overkill. Again, a matter of tase. The example above might be more compelling, at least to me, if A instantiated B directly ('new B()'). That's not a matter of taste, that's definitely a bad concrete class dependency! And a good argument for using Pico, no matter what one's tastes are.

    I'll have to check out JMock and your plugin.

    [OFFTOPIC]
    Pico is great! Picofying our code is really pointing out (and fixing) a lot of bad dependencies. (But sometimes we use the single argument version of registerComponentImplementation. ) I have a lot of questions though. Is there a general Pico discussion area or list? If not, what is the best list to post newbie questions too?

    Thanks!

    Steve

  6. Mar 04, 2004

    Aslak Hellesøy says:

    The official list can be found here:

    The official list can be found here: http://lists.codehaus.org/mailman/listinfo/picocontainer-dev
    (Due to spam attacks you must be subscribed to be able to post)

    Please note that we will eventually remove these comments and integrate the questions and answers into the page itself as more official "docs".