I’m sure you’ve heard this idea before: all the public methods of an object should come from interfaces. I very much agree with it and, if you ask me, I’ll tell you that all objects, without exception, should implement at least one interface. This is of paramount importance, especially when developing libraries and reusable components. You want to provide extensibility and testability, you want to let your users decorate or reimplement objects etc.

But what about standalone applications, where you have objects that represent things which can have only one implementation? Even those? Yes. Let’s see why, through an example.

A Mouse In The House
Tom & Jerry - A Mouse In The House, by William Hanna and Joseph Barbera

Assume your application reads some configs from a .yml file. You introduce the following object immediately:

/**
 * Configuration in YAML format.
 */
public class ConfigYml {

  /**
   * Config in YAML format.
   */
  private final Yaml config;

  /**
   * Should the bot tweet its actions?
   */
  public Boolean tweet() {
    return Boolean.valueOf(this.config.scalar("tweet"));
  }

  /**
   * Who can give commands to the bot?
   */
  public List<String> commanders() {
    return this.config.sequence("commanders");
  }
}

One argument for interface Config would be the following: what if, later, you decide to read the config from XML? Then you would have another implementation called ConfigXml. It’s a good reason but you won’t do it because, when the time for change comes, you will simply modify the ConfigYml class above – it’s very unlikely that you will ever have both XML and YAML configs. I would think the same.

Still, I would introduce it for another reason: the case when the file .config.yml is missing. Here’s how your code would look without an interface:

public void handleCommand(final Command com) {
  final ConfigYml config = com.config();
  if(config != null) {
    if(config.tweet()) {
      //tweet
    }
    for(String commander : config.commanders()) {
      //do something about commanders.
    }
  } else {
    //handle missing config sitiuation, probably duplicate the logic in the if()
  }
}

Method Command.config() returns null if there is no config, thus complicating method handleCommand a lot. It is inevitable. What else to return besides null? And you have to check for it and cover the exceptional case.

However, if you had interface Config, you would realize that it should have a Missing implementation:

public class Missing implements Config {
  @Override
  public List<String> commanders() {
    return new ArrayList<>();
  }

  @Override
  public boolean tweet() {
    return false;
  }
}

With this approach, an object of type Missing represents the case when the config file is not there. We won’t have to return null or do any other type of if/else forking in our code. We just call command.config() to fetch the configuration, and we know that all the cases are covered. The handleCommand method becomes much smaller (it’s still far from a perfect design, though)

public void handleCommand(final Command com) {
  final Config config = com.config();
  if(config.tweet()) {
    //tweet
  }
  for(String commander : config.commanders()) {
    //do something about commanders.
  }
}

The Missing configuration in the above example returns false for tweeting and an empty list of commanders. Maybe you would like your application to throw an exception if the config is missing, so you should have the implementation Mandatory, which throws an exception when either of the methods is called.

You see? This is why interfaces are important. If it wasn’t for the Config interface, the code would be polluted with if/else forks for null checking and/or for exception throwing. Also, you can easily use the decorator pattern to add more functionality: maybe you only want to use the commanders which are admins – there are dozens of possiblities which you wouldn’t see if there was no interface there.

Another way of putting it is the following: objects must do as much work for you as possible. You should ask an object to do something, rather than ask for data and manipulate it yourself. This is a core principle in OOP, which is very hard to apply when you don’t use interfaces. Objects Missing and Mandatory handle very important things for us, relieving us of useless logic and making the code more maintainable and testable.

To conclude, just keep in mind: declare interfaces for any object, even if you don’t see a real use for it at first. You will surely see it later, when trying to use that object. Any questions?