Abstract Class design pattern and its use in Java

This tutorial will show you what is Abstract Class Pattern and when we consider to use this Abstract Class Design Pattern in our application design.

The abstract class design pattern is useful for designing a framework for the consistent implementation of the functionality common to a set of related classes.

An abstract class consists of one or more abstract methods that are only declared but contains no implementations that indicate variable parts of the class functionality.

An abstract class may contain non-abstract methods that indicate non-variable parts of the class functionality. Later different classes are designed when abstract methods outlined in an abstract class need to be implemented to provide different functionality.

An abstract class may not be directly instantiated. Hence when a class is designed as a non-abstract subclass of an abstract class, it must implement all abstract methods a parent abstract class contains.

It is mandatory for a concrete subclass of an abstract class to implement all of its abstract methods in a consistent manner in terms of the method signatures.

The implemented methods in the parent abstract class are automatically inherited by all subclasses. Thus it eliminates the redundant coding in all subclasses.

The below figure shows an abstract class with three subclasses.Abstract Class pattern in Java

In Java programming language there is no support for multiple inheritance so a class can inherit only from one single class. Hence inheritance should be used only when it is absolutely necessary.

Whenever possible, methods denoting the common behavior should be declared in a Java interface and those methods need to be implemented by different implementer classes when required.

But interfaces suffer from the limitation that they cannot provide method implementations. It means that every implementer of an interface must explicitly implement all methods declared in an interface, even when some of these methods represent the invariable part of the functionality and have exactly the same implementation in all of the implementer classes and it leads to redundant code.

The following example demonstrates how the Abstract Class design pattern can be used in such cases without requiring redundant code.

Example

In a typical organization, it is very common to have employees with different designations. This can be represented in form of a class hierarchy with a base Employee class and a set of subclasses each corresponding to employees with a specific designation.

Let us consider the following operations as part of designing the representation of an employee.

  1. Save employee data
  2. Display employee data
  3. Access employee attributes such as employee name and employee ID
  4. Calculate compensation

While operation 1 through operation 3 remain same for all employees, the compensation calculation will be different for employees with different designations.

Such an operation, which can be performed in different ways, is a good candidate to be declared as an abstract method.

This forces different concrete subclasses of the Employee class to provide a custom implementation for the salary calculation operation.

From the base Employee class implementation in the below class, it can be seen that the base Employee class provides implementation for the save(), getEmployeeID(), getEmployeeName() and toString() methods while it declares the computeCompensation() method as an abstract method.

public abstract class Employee {
	String emploeeID;
	String employeeName;
	//invariable parts
	public Employee(String emploeeID, String employeeName) {
		this.emploeeID = emploeeID;
		this.employeeName = employeeName;
	}
	public String getEmployeeID() {
		return emploeeID;
	}
	public String getEmployeeName() {
		return employeeName;
	}
	@override
	public String toString() {
		return "Employee Name :: " + getEmployeeName() + ", Employee ID :: " + getEmployeeID();
	}
	public void save() {
		//save to either file or db or any persistance storage
	}
	//variable part of the behavior
	public abstract String computeCompensation();
}

Let us define two concrete subclasses — RecruitmentManager and HumanResource — of the Employee class representing employees who are recruitment manager and human resource, respectively.

Each of these subclasses must implement the computeCompensation() method. Otherwise these subclasses need to be declared as abstract and it becomes impossible to instantiate them.

public class RecruitmentManager extends Employee {
	public RecruitmentManager(String emploeeID, String employeeName) {
		super(emploeeID, employeeName);
	}
	public String computeCompensation() {
		return "Recruitment Manager's salary is :: base + over time + commission - tax deduction";
	}
}
public class HumanResource extends Employee {
	public HumanResource(String emploeeID, String employeeName) {
		super(emploeeID, employeeName);
	}
	public String computeCompensation() {
		return "Human Resource's salary is :: base + special allowance - tax deduction";
	}
}

The below figure shows the class hierarchy with RecruitmentManager and HumanResource concrete subclasses of the Employee class.

Abstract Class pattern in Java

Interface versus Abstract Class

As an alternate design strategy, we could have designed the employee representation as a Java interface instead of designing as an abstract class with both the RecruitmentManager and the HumanResource classes as its implementers.

The below figure shows the resulting class hierarchy. But doing so would require both the implementers to implement the save, getEmployeeID(), getEmployeeName(), toString() and the computeCompensation() methods because the implementations for all methods remain same for all implementers and this leads to redundant code in the application.

The implementation of these invariable methods cannot be made part of the Employee interface because a Java interface can be used for declaration purpose only.

By designing the Employee class as an abstract class, the need for a redundant code can be eliminated.

Abstract Class pattern in Java

That’s all. Thanks for reading.

Leave a Reply

Your email address will not be published. Required fields are marked *