Interfaces

From Team 449 Wiki

In java, an interface is (more-or-less) a defined list of public method signatures. Classes can then be declared to "implement" the interface, requiring that they provide an implementation for each method in the interface. Other code can then be written to use the interface, rather than the underlying object. Thus, like inheritance, interfaces provide a form of polymorphism. It is helpful think of the interface as a "contract" that implementing classes fulfill - code that uses the interface does not care how the contract is fulfilled, and thus does not care which implementing class is used.

Designing to an Interface

In all engineering, a near-universal design principle is that form follows from required function. One must first determine the requirements of a project prior to design, and design choices are made in service of those requirements.

This principle also holds true when designing code. An interface, as it specifies a "contract" fulfilled by implementing classes, can naturally be thought of as a list of requirements. Implementing classes should be built to satisfy those requirements. In other words, you should program classes to an interface - that is, the interface should be thought out first, and the implementing class built to satisfy it. Working the other way around (building the class "bottom-up" - implementation first - and then deciding which pieces should be publicly-exposed) may result in confusing, bloated, or inflexible classes.

When you design an interface, you're designing the "public face" of whatever classes are going to implement that interface - literally, the interface through which other code will interact with the implementing classes. Just like the interface for a website or app, you want it to have everything needed to do the task at hand, and nothing else that clutters it up. This doesn't mean trying to cram the functionality you need into as few functions as possible, but just trying to avoid bloat that confuses future programmers who want to use that interface.

In fact, this type of thinking is not only for classes that implement explicitly-defined interfaces - it can and should be applied to all classes you write. Every class can be thought of as having an "implicit" interface consisting of its public methods and fields. Likewise, it is almost always prudent, when possible, to first determine what other code needs to access from the class, and then program the class to the resulting "interface."

Top-down Design

It is often easiest to build to an interface if your code is designed "top-down." This means starting by writing the code that will call or depend on other code - this will naturally reveal the contracts required from the lower-level code as work your way down from the top. In our framework, this would mean designing a command first, then the interface used by the command, and then lastly the subsystem implementing the interface. This ensures you only write what you need, because you know what each class needs to do before you start writing it. Top-down design isn't always possible, but when it is, you should do it. When it isn't possible and you have to write bottom-up, make sure to go back later and look at it from a top-down perspective and get rid of all the clutter. IntelliJ helps you out with this by telling you which methods are unused or can be made private.