Interfaces and Abstract Classes in Java

Malina Tran
Tech and the City
Published in
3 min readSep 7, 2016

Every language has its own solution to dealing with different types. With Ruby, it’s inheritance. With Clojure, it’s protocols. Java also has its own version of template modeling pattern, which is a way to remove code duplication while linking related objects. This technique involves higher-level abstractions and can help define the code’s design. The thing is: does it make sense to implement an interface or abstract class?

Before we distinguish between the two, let’s talk about use cases. Last week, I had undertaken some major refactoring. Most of it involved creating interfaces. A little bit about Java interfaces: they only contain method signatures (name, parameters, and exceptions) and fields. They do not store any implementation details.

A class implements an interface, which formalizes the behavior it promises to provide. Interfaces form a contract between the class and the outside world, and this contract is enforced at build time by the compiler. All of the methods defined by that interface must be in its respective classes for compilation to be successful.

The first instance of doing so, with my Java server project, is abstracting the reader and writer objects responsible for reading from, and writing to, the client socket. Doing so enables flexibility in the type of reader/writer classes that we implement. This is ideal for the program, but also for testing. We can pass classes that implement reader and writer interfaces, but we can also pass in mock classes for testing.

Secondly, the Java server needs to process a series of routes and to determine an action based on that unique route. Originally, I had set up a conditional statement that I knew would just end up catastrophically if continued. I decided to setup a hash-map that would store the route (as its key) and callback function (as its value). Rather than call each function based on the route (e.g. if it’s a “GET /”, then execute “IndexRouterAction”), it made sense that the code should eschew a conditional statement and call the respective callback function without necessarily needing to know which one it is calling.

In my previous tic-tac-toe games, `ComputerPlayer` and `HumanPlayer` were linked by their super class, `Player`, and therefore had the same methods. This allowed me to call on the current player to make a move, rather than do some kind of type-checking; as in, if the current player is the computer, call on the computer to make a move. This does not follow object-oriented standards given that it can easily become an overwrought case or conditional statement if we had multiple players.

Let’s talk about key differences between abstract classes and interfaces. If there will be frequent changes in the code’s design, it is recommended to use interfaces. It seems that using interfaces is the default but there are times that call for abstract classes, e.g. when a method is the same for each class that is implementing the interface. There is a really good example in this Stack Overflow post.

Abstract classes allows you to define some behaviors while relying on subclasses to provide others; they’re an ideal solution for inherited hierarchies. For instance, an abstract class may provide default services such as event and message handling, which can be plugged into an application framework. However, there is some application-specific functionality like startup and shutdown tasks, which often depends on the application. Rather than define that behavior itself, the abstract base class can declare abstract shutdown and startup methods. An abstract class doesn’t know how to perform those actions, only that it has to initiate the actions. When the startup method is called in the abstract base class, the method defined in the child class is invoked.

I’ve come to terms with the fact that I may not have the foresight to use interfaces or abstract classes as an immediate solution. Understandably so, it comes with more experience and enabling the design to be driven by the code.

--

--