Subclassing an abstract class

From the Oracle Java documentation:

An abstract class is a class that is declared abstract—it may or may not include abstract methods. Abstract classes cannot be instantiated, but they can be subclassed.

Abstract classes can be useful where multiple classes share similar methods or fields[1]. In some programming scenarios, multiple classes should always implement a common method from a superclass. In such cases, declaring the superclass and common method as abstract will ensure consistent behavior.


Creating and using an abstract class

For this demonstration, I will be using code copied from my Benson project*. In short, Benson is a small project that enables people to control various electronics via voice. When someone speaks to Benson, he attempts to match the spoken words to keywords within a predefined list of queries. Each query should require different keywords and respond differently from one another however, each query must have keywords and responses. This is the quintessential usage case for an abstract class, see the code below*.

public abstract class Query {

    public abstract List<String> getInputs();

    public abstract Response getResponse();
    
}

In the above abstract class, we have two abstract methods. It should be noted that abstract methods cannot have a body. Each potential query that Benson will iterate through will subclass the above Query class. The following code will demonstrate this.

public class Hello extends Query {

    @Override
    public List<String> getInputs() {

        return Arrays.asList("hello", "hey", "hi", "howdy");

    }

    @Override
    public Response getResponse() {

        return new Response("Hello there!");

    }

}

The above code represents a simple extension of the abstract Query class. Notice that both abstract methods defined in the Query class are overridden here and return actual values. Benson will iterate through a list of various subclasses that extend our abstract Query class and use both of the abstract methods to respond to speech. To demonstrate how this is done, review the following code.

List<? extends Query> lexicon = Arrays.asList(new Hello(), 
        new Goodbye());

for (Query query : lexicon) {

    for (String input : query.getInputs()) {

        if (speech.contains(input)) {

            say(query.getResponse());

            return;

        }

    }
    
}

The above code demonstrates how Benson responds to speech. First, we create a list of every subclass we want to include in his lexicon. You will notice the Hello class we discussed earlier is defined here as well as a Goodbye class that was not discussed. When Benson receives spoken text, he iterates through this list of Query subclasses in attempt to find the spoken text defined as an input. If the speech matched an input of a Query subclass, the response is retrieved from the Query and then spoken.


Conclusion

Abstract classes can prove to be very useful for writing reusable code. Subclassing an abstract class in place of using different classes with similar methods may significantly reduce lines of unnecessary code. In my opinion, less code translates into less opportunity for bugs so be sure to ask yourself if you can extend an abstract class whenever you find yourself in need of multiple classes that share methods.


Further reading

A JavaCodeGeek example.

A JavaCoffeeBreak example.

A StackExchange discussion.


References

[1] http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html <Accessed on March 6, 2015>

* All code used in this post is modified from Benson’s source code for simplicity

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s