"Head First Design Patterns" study notes - Template Method Pattern

Template Method pattern.

Case

Tea and coffee is very similar to the steps, the steps of coffee:

  1. Boil the water
  2. Coffee brewed with boiling water
  3. She poured coffee into a cup
  4. Sugar and milk

Tea steps:

  1. Boil the water
  2. Tea with boiling water immersion
  3. The tea poured into the cup
  4. With lemon

So the coffee code is as follows:

public class Coffee {

    void prepareRecipe() {
        boilWater();
        brewCoffeeGrinds();
        pourInCup();
        addSugarAndMilk();
    }

    public void boilWater() {
        System.out.println("Boiling water");
    }

    public void brewCoffeeGrinds() {
        System.out.println("Dripping Coffee through filter");
    }

    public void pourInCup() {
        System.out.println("Pouring into cup");
    }

    public void addSugarAndMilk() {
        System.out.println("Adding Sugar and Milk");
    }
}

Tea code:

public class Tea {
    
    void prepareRecipe() {
        boilWater();
        steepTeaBag();
        pourInCup();
        addLemon();
    }

    public void boilWater() {
        System.out.println("Boiling water");
    }

    public void steepTeaBag() {
        System.out.println("Steeping the tea");
    }
    
    public void addLemon() {
        System.out.println("Adding Lemon");
    }
    
    public void pourInCup() {
        System.out.println("Pouring into cup");
    }
}

It's obvious duplication of code, so we can extract the common parts:

  1. Boil the water
  2. With hot coffee or tea
  3. The drinks poured into a cup
  4. Add the appropriate spices in the beverage

The first step and the third step is public and can be withdrawn, while the second step and the fourth step is not the same place, only a drink or seasoning just not the same.

We first 3-step drawn into the superclass.

public abstract class CaffeineBeverage {
    
    public abstract void prepareRecipe();

    public void boilWater() {
        System.out.println("Boiling water");
    }

    public void pourInCup() {
        System.out.println("Pouring into cup");
    }
}

However, 2,4-step is very similar, so we are also defined in the superclass, modify it and then see.

public abstract class CaffeineBeverage {

    public final void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }

    protected abstract void addCondiments();

    protected abstract void brew();

    public void boilWater() {
        System.out.println("Boiling water");
    }

    public void pourInCup() {
        System.out.println("Pouring into cup");
    }
}

We put two steps 2,4 abstraction, and other sub-categories to achieve their specific functions. After transformation as tea and coffee.

public class Tea extends CaffeineBeverage {

    @Override
    protected void addCondiments() {
        System.out.println("Adding Lemon");
    }

    @Override
    protected void brew() {
        System.out.println("Steeping the tea");
    }
}

public class Coffee extends CaffeineBeverage {

    @Override
    protected void addCondiments() {
        System.out.println("Adding Sugar and Milk");
    }

    @Override
    protected void brew() {
        System.out.println("Dripping Coffee through filter");
    }
}

Tea and coffee are inherited from caffeine drinks, they are required to implement brew () and addCondiments () method themselves. This is the template method pattern, preareRecipe () method is our template, it is used as a template algorithm, the algorithm refers to the production of caffeine beverages. Each step of the algorithm are a way to represent. The method steps a template defines the algorithms and allow subclasses provide an implementation for one or more steps.

definition

Template Method pattern defines a skeleton algorithm In one method, some steps to subclasses delay. Template methods such subclasses without changing the structure of the algorithm, some of the steps of the algorithm are redefined.

In fact, similar steps out of several similar classes have, these steps can be abstract, implemented by subclasses, this algorithm can ensure that the structure remains unchanged, while providing a partially achieved by subclasses.

We can also hook is set, the statement to our abstract class or hollow default implementation of the method. Subclass can be left room for expansion, so that subclasses have the ability to point to a different algorithm is not the same step, specific or not linked to the subclass. Let us first an example:

public abstract class CaffeineBeverageWithHook {
    
    void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        if (customerWantsCondiments()) {
            addCondiments();
        }
    }

    private boolean customerWantsCondiments() {
        return true;
    }

    protected abstract void addCondiments();

    protected abstract void brew();

    public void boilWater() {
        System.out.println("Boiling water");
    }

    public void pourInCup() {
        System.out.println("Pouring into cup");
    }
}

We added a conditional statement, the condition is () method returns a value determined by the customerWantsCondiments. If the customer wants to spices, returns true, execution addCondiments () method, which is a hook, a subclass can override this method, but not necessarily must be covered. We continue to modify our code:

public class CoffeeWithHook extends CaffeineBeverageWithHook {
    @Override
    protected void addCondiments() {
        System.out.println("Adding Sugar and Milk");
    }

    @Override
    protected void brew() {
        System.out.println("Dripping Coffee through filter");
    }

    public boolean customerWantsCondiments() {
        String answer = getUserInput();

        if (answer.toLowerCase().startsWith("y")) {
            return true;
        } else {
            return false;
        }
    }

    private String getUserInput() {
        String answer = null;

        System.out.println("Would you like milk and sugar with your coffee (y/n)?");

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        try {
            answer = br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (answer == null) {
            return "no";
        }
        return answer;
    }
}

First, we achieve the BREW () and addCondiments () method, and then covering the customerWantsCondiments () method, the user input y for user needs to add milk and sugar, n-contrary, we now executing the test program.

public class BeverageTestDrive {
    public static void main(String[] args) {
        CoffeeWithHook coffeeWithHook = new CoffeeWithHook();
        coffeeWithHook.prepareRecipe();
    }
}

Very convenient, right hook, in fact, we can also set it directly to the superclass.

We now have a new design principle: "Hollywood principle."

Hollywood principle: Do not call (call) us, we will call (call) you.

Allow low-level components to hook themselves onto the system, but the high-level assembly will decide when and how to use these low-level components. In other words, high-level components to treat low-level components of way, "Do not call us, we'll call you."

Java in the template method pattern

Sort by template method, sort the array (Object [] a) sorting method is the way we look at its code.

public static void sort(Object[] a) {
	Object[] aux = (Object[])a.clone();
	mergeSort(aux, a, 0, a.length, 0);
}

This method is just a helper method is used to create a copy of the array, then passes it to the mergesort () method.

private static void mergeSort(Object src[], Object dest[], int low, int high, int off) {
	for (int i=low; i<high; i++) {
		for (int j=i; j>low && ((Comparable)dest[j-1].compareTo((Comparable)dest[j])>0; j--) {
			swap(dest, j, j-1);
		}
	}
	return;
}

This method comprises sorting algorithm that relies on the compareTo () method implementation algorithm is completed. Here you can think of it as a template method, you need to implement compareTo () method. Now look at an example. Compare the person's age, we need a man of class.

public class People implements Comparable {
    String name;
    int age;

    public People(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Object o) {
        People o1 = (People) o;
        return Integer.compare(this.age, o1.age);
    }
}

test program.

public class PeopleSortTestDrive {
    public static void main(String[] args) {
        People[] people = {
                new People("Ab", 12),
                new People("zhangsan", 123),
                new People("lisi", 22),
                new People("wangwu", 53),
                new People("zhaoliu", 66)
        };
        System.out.println("Before sorting: ");
        display(people);
        Arrays.sort(people);
        System.out.println("\nAfter sorting:");
        display(people);
    }

    public static void display(People[] people) {
        for (People person : people) {
            System.out.println(person);
        }
    }
}

The first print is out of order, second order is from small to large. This shows that we are sort of success, the key step is to realize our compareTo method of the Comparable interface in our class by Integer compare (int x, int y) method to achieve more, so eventually the entire array can perfect the sort is complete .

Write a program window of Swing

The next example is Swing's JFrame! JFrame is the most basic Swing container, inherited a paint () method, paint the default state () do not do things because it is a hook, cover it, we will be able to put their own code into the JFrame algorithms .

public class MyFrame extends JFrame {
    public MyFrame(String title) {
        super(title);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        this.setSize(300, 300);
        this.setVisible(true);
    }

    public void paint(Graphics graphics) {
        super.paint(graphics);
        String msg = "I rule!!";
        graphics.drawString(msg, 100,100);
    }

    public static void main(String[] args) {
        new MyFrame("Head First Design Patterns");
    }
}

We use the paint () hook method, add the code for our own definition, but also the appearance of the application mode.

Published 26 original articles · won praise 2 · Views 2324

Guess you like

Origin blog.csdn.net/qq_42909545/article/details/105008722