A constructor is not part of a class’s interface

Peter Provost and I were talking today about some code that we’re working on together. We’re constructing a class right now, called a Starter. The job of a Starter is to stitch together a Repository, a class whose job it is interact with a source control repository, subversion in our case, a Builder, which is responsible for causing a Project to be built, and a BuildLogger. All of this stuff has to be aware of configuration changes, so we also  have to pass in a Configuration object that is able to tell us the current configuration values. The constructor signature looks like this:

public Starter(IStarterConfiguration, IRepository, IBuilder, IBuildLogger) // excuse the shorthand

When I write code, I typically have constructors that look like this. I believe that it is not the job of the class to know where its bits and pieces come from, because this would tightly couple the Starter class to specific types of configs, repositories, etc, which is a bad thing. So, I frequently have a different class, like a factory or a builder whose job it is to construct the objects and send them along their merry way. Creating code like this lets me keep the methods of the class as clean as possible, and allows me to vary the actual type of objects passed in.

The downside of this is that construction of my objects can get a little complicated. My constructors can end up taking several different kinds of objects that are really only exposed because I want to avoid the tight coupling. But I don’t consider this to be a problem.

Others do not share my opinion.

I believe that the interface of the class are only that class’s member functions and properties. Constructors are not part of the interface. Constructors never appear in an interface, and are not what typical clients use. They just call the regular methods.

It turns out that this style of creating classes creates systems that are amenable to dependency injection techniques, both manually and through using tools like pico. This lets you create flexible systems at the price of exposing some of your implementation through constructor arguments. I haven’t played with tools like this yet, but I’m starting to get the itch…

Sorry for the rambling, but that’s what was on my mind today.

— bab

 

9 thoughts to “A constructor is not part of a class’s interface”

  1. the problem with setter-getter or attribute based dependancy injection is that its hard to publish the valid sets of attributes that need to be set before one can start using the class.

    btw, i think the constructor is part of a class’ interface (all classes have them), its just not part of an interface (public interface fubar) definition. i believe uml uses the ‘create’ word to signify constructors.

  2. I agree with Saad’s criticism of attribute-based injection. It takes communal knowledge to know how to construct objects. And if it changes, the compiler can’t help you find what needs to be changed. Constructors are there to specify all the moving parts.

    Saad, the reasons why I don’t consider the ctor as part of a classes interface are because they don’t show up in any interface that is passed around. The consumers of that interface have no idea how object is built — they just use it.

    The object responsible for constructing an object is not necessarily the same one that constructs. Two different responsibilities implies two different classes.

    Just my opinion 🙂

    bab

  3. I think it comes down to "will I break code if I change this"? Will version 2.2 of my software possibly break people coding against version 2.1?

    If you expose your concrete class to clients, then the constructor is part of the interface/API. You cannot change it without making the new version of your class incompatible with the prior version.

    If you only expose the "interface", say through a factory, then you can do whatever you like with the constructor. Clients never see it and it truly is not part of your API.

    Of course you know all of this…much of this is a matter of coming up with the right words to describe the problem. This one is a bit tricky because the word "interface" is both a language keyword as well as a concept describing the signature of the class. Someone who is thinking literally of the language keyword "interface" is right to argue that a constructor is not part of the "interface".

  4. I agree with Eric. They way you get around the client knowing about the constructor is by hiding the creation behind a factory. With IOC implementations this typically goes away and DI takes it’s place. If you follow this approach, the client needs to react just as much to the constructor change as it would an "interface" change.

    Personally, I prefer that constructors fully populate an object. The problem comes in when the you add a must have attribute. Do you create another constructor that accomodates this and deprecate the old one? It’s really a judgement call and there isn’t a right or wrong answer. It just depends.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.