Design patterns for abstract classes and template methods

Posted by hebisr on Fri, 17 May 2019 20:05:57 +0200

Abstract methods and abstract classes

Abstract classes: classes modified with abstract modifiers, such as:

public abstract class GeneralService {
    
}

Abstract method: Abstract modifier modified method, abstract method can not have method body, such as:

public abstract void service();

The rules for abstract classes and methods are as follows:

  1. Must be modified with abstract modifiers
  2. Abstract classes do not necessarily contain Abstract methods, but classes containing abstract methods must be abstract classes.
  3. Abstract classes cannot be instantiated
  4. The constructor of an abstract class cannot be used to create objects, but is mainly used to be called by its subclasses.

The following defines a Shape Abstract class:

/**
 * Define an abstract class to describe the "shape" of abstract concepts
 */
public abstract class Shape {

    // Shape color
    private String color;

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    // Parametric constructor
    public Shape(String color) {
        this.color = color;
    }

    // Define an abstract method for calculating perimeter
    public abstract double calPerimeter();
}

The Shape class above contains an abstract method, calPerimeter(), so the Shape class can only be an abstract class. Shape classes contain both initialization blocks and constructors, but these are not called when creating Shape objects, but when creating its subclass objects.

Next, we define a Triangle class and a Circle class to inherit the Shape class and implement the abstract method calPerimeter() in Shape.

/**
 * Define a triangle class that inherits from the shape class
 */
public class Triangle extends Shape {

    // Define three edges of a triangle
    private double a;
    private double b;
    private double c;

    public Triangle(String color, double a, double b, double c) {
        super(color);
        this.a = a;
        this.b = b;
        this.c = c;
    }

    @Override
    public double calPerimeter() {
        return a + b + c;
    }
}
/**
 * Define a circular class that inherits from the shape class
 */
public class Circle extends Shape {

    // Define the radius of a circle
    private double radius;

    public Circle(String color, double radius) {
        super(color);
        this.radius = radius;
    }

    @Override
    public double calPerimeter() {
        return 2 * Math.PI * this.radius;
    }
}

Shape (shape) class is an abstract concept. Triangle (triangle) class and Circle (circle) class are the representations of Shape. They both implement Shape's calPerimeter() method. The formulas for calculating perimeter are different.

The following are the test classes:

/**
 * Test class
 */
public class Test {
    public static void main(String[] args) {
        Shape s1 = new Triangle("yellow", 3.0, 4.0, 5.0);
        Shape s2 = new Circle("gules", 3);
        System.out.println("Triangle s1 Color:" + s1.getColor() + ",Perimeter:" + s1.calPerimeter());
        System.out.println("circular s2 Color:" + s2.getColor() + ",Perimeter:" + s2.calPerimeter());
    }
}

Output results:

Triangle s1 color: yellow, circumference: 12.0
 Round s2 color: red, circumference: 18.84955592153876
  • When using abstract to modify a class, it means that the class is abstract and can only be inherited; when using abstract to modify a method, it means that the method must be implemented (rewritten) by its subclasses.
  • Final-modified classes cannot be inherited, final-modified methods cannot be overridden, so final and abstract cannot be used simultaneously.
  • When using static to decorate a method, it means that the method is a class method, which can be called directly by the class without creating objects. But if the method is defined as abstract, it will lead to errors when calling the method through the class (calling a method without a method body will certainly cause errors), so static and abstract cannot modify a method at the same time.
  • The abstract keyword modification method must be overridden by its subclasses in order to be meaningful. Therefore, the abstract method cannot be defined as private access rights, that is, private and abstract can not modify a method at the same time.

The role of abstract classes

Abstract class is the parent class abstracted from many concrete classes. It has a higher level of abstraction, describing the commonness of a group of things.

Abstract classes are common templates for many subclasses. Subclasses are extended and modified on the basis of abstract classes. However, subclasses generally retain the behavior of abstract classes.

Template Method Patterns

If you write an abstract parent class, the parent class provides a common method for multiple subclasses and leaves one or more methods to its subclasses to implement. This is the template pattern, which is a very common and simple design pattern.

A slightly more professional definition is:

Template method pattern defines the skeleton of an algorithm in a method and delays some steps to subclasses. Template method enables subclasses to redefine some steps in the algorithm without changing the structure of the algorithm.

Here's another example of a template approach pattern, in which we divide the cooking process into three steps:

  1. Spare parts
  2. Cook
  3. Loading

These three parts are the skeleton of the algorithm. However, different dishes need different ingredients, cooking methods, and how to plate. When making different dishes, different implementations are needed.

Let's write an abstract cooking parent class with the following code:

/**
 * Define the abstract class of cooking
 */
public abstract class DodishTemplate {    
    /**
     * Template method encapsulates the cooking algorithm
     * Modify with final keywords to avoid subclasses modifying the order of algorithms
     * The template method defines a series of steps, each represented by a method.
     */
    protected final void dodish(){
        this.preparation();
        this.doing();
        this.sabot();
    }
    
    /**
     * Spare parts
     */
    public abstract void preparation();
    
    /**
     * Cook
     */
    public abstract void doing();
    
    /**
     * Loading
     */
    public abstract void sabot();
}

Next, we define how to make scrambled eggs with tomatoes and braised meat with red sauce and realize the abstract method in the parent class.

/**
 * Making scrambled eggs with tomatoes
 */
public class EggsWithTomato extends DodishTemplate{

    @Override
    public void preparation() {
        System.out.println("Wash and cut tomatoes and beat eggs.");
    }

    @Override
    public void doing() {
        System.out.println("Pour the eggs into the pot and stir-fry the tomatoes.");
    }

    @Override
    public void sabot() {
        System.out.println("Scrambled eggs and tomatoes are put into a dish and sprinkled with scallions.");
    }
}
/**
 * Making red-roasted meat
 */
public class Bouilli extends DodishTemplate{

    @Override
    public void preparation() {
        System.out.println("Cut pork and potatoes.*");
    }

    @Override
    public void doing() {
        System.out.println("Stir-fry the cut pork in the pan for a while and then pour the potatoes into the pan and stew.");
    }

    @Override
    public void sabot() {
        System.out.println("Pour the cooked red meat into a bowl and sprinkle with white sesame seeds.");
    }
}

In the test class, we cook dishes:

public class App {
    public static void main(String[] args) {
        DodishTemplate eggsWithTomato = new EggsWithTomato();
        eggsWithTomato.dodish();
        
        System.out.println("-----------------------------");
        
        DodishTemplate bouilli = new Bouilli();
        bouilli.dodish();
    }
}

Operation results:

Wash and cut tomatoes and beat eggs.
Pour the eggs into the pot and stir-fry the tomatoes.
Scrambled eggs and tomatoes are put into a dish and sprinkled with scallions.
-----------------------------
Cut pork and potatoes.
Stir-fry the cut pork in a pan for a while and then pour the potatoes into the pan and stew.
Pour the cooked red meat into a bowl and sprinkle with white sesame seeds.

From this example, we can see that the DodishTemplate class defines a general algorithm for cooking, while some specific implementation details are deferred to its subclasses (EggsWithTomato and Bouilli). That is, the template method defines the steps of an algorithm and allows subclasses to provide implementations for one or more steps.

Topics: Java