首页 > 代码库 > 设计模式 - 模板方法模式(template method pattern) 详解

设计模式 - 模板方法模式(template method pattern) 详解

模板方法模式(template method pattern) 详解


本文地址: http://blog.csdn.net/caroline_wendy


模板方法模式(template method pattern): 在一个方法中定义一个算法的骨架, 而将一些步骤延迟到子类中. 

模板方法使得子类可以在不改变算法结构的情况下, 重新定义算法中的某些步骤.


模板方法可以进行挂钩(hook), 钩子(hook)是一种被声明在抽象类中的方法, 但只有空的或者默认的实现.

钩子的存在, 可以让子类有能力对算法的不同点进行挂钩.


抽象类的框架:

/**
 * @time 2014年6月18日
 */
package template_method;

/**
 * @author C.L.Wang
 *
 */
public abstract class AbstractClass {
	
	final void templateMethod() {
		primitiveOperation1();
		primitiveOperation2();
		concreteOperation();
		hook();
	}
	
	abstract void primitiveOperation1();
	
	abstract void primitiveOperation2();
	
	final void concreteOperation() {
		
	}
	
	void hook() {}
}


面向对象原则:

好莱坞原则: 别调用我们, 我们会调用你.


具体方法:

1. 抽象类(abstract class), 包含模板方法(template method), 抽象操作(abstract operation)

具体操作(concrete operation), 和钩子(hook).

/**
 * @time 2014年6月18日
 */
package template_method;

/**
 * @author C.L.Wang
 *
 */
public abstract class CaffeineBeverage {
	
	final void prepareRecipe() { //模板方法
		boilWater();
		brew();
		pourInCup();
		if(customerWantsCondiments()) {
			addCondiments();
		}
	}
	
	abstract void brew(); //抽象操作
	
	abstract void addCondiments();
	
	void boilWater() { //具体操作
		System.out.println("Boiling water");
	}
	
	void pourInCup() {
		System.out.println("Pouring into cup");
	}
	
	boolean customerWantsCondiments() { //钩子
		return true;
	}
	
}

2. 具体类(concrete class), 继承(extend) 抽象类(abstract class).

/**
 * @time 2014年6月18日
 */
package template_method;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * @author C.L.Wang
 *
 */
public class CoffeeWithHook extends CaffeineBeverage {

	/* (non-Javadoc)
	 * @see template_method.CaffeineBeverage#brew()
	 */
	@Override
	void brew() {
		// TODO Auto-generated method stub
		System.out.println("Dripping Coffee through filter");
	}

	/* (non-Javadoc)
	 * @see template_method.CaffeineBeverage#addCondiments()
	 */
	@Override
	void addCondiments() {
		// TODO Auto-generated method stub
		System.out.println("Adding Sugar and Milk");
	}
	
	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 in = new BufferedReader(new InputStreamReader(System.in));
		
		try {
			answer = in.readLine();
		} catch (IOException ioe) {
			System.out.println("IO error trying to read your answer");
		}
		
		if (answer == null) {
			return "no";
		}
		
		return answer;
	}
	
}


/**
 * @time 2014年6月18日
 */
package template_method;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * @author C.L.Wang
 *
 */
public class TeaWithHook extends CaffeineBeverage {

	/* (non-Javadoc)
	 * @see template_method.CaffeineBeverage#brew()
	 */
	@Override
	void brew() {
		// TODO Auto-generated method stub
		System.out.println("Steeping the tea");
	}

	/* (non-Javadoc)
	 * @see template_method.CaffeineBeverage#addCondiments()
	 */
	@Override
	void addCondiments() {
		// TODO Auto-generated method stub
		System.out.println("Adding Lemon");
	}

	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 lemon with your tea (y/n)? ");
		
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		
		try {
			answer = in.readLine();
		} catch (IOException ioe) {
			System.out.println("IO error trying to read your answer");
		}
		
		if (answer == null) {
			return "no";
		}
		
		return answer;
	}
	
}

3. 测试类, 包含钩子(hook)操作.

/**
 * @time 2014年6月18日
 */
package template_method;

/**
 * @author C.L.Wang
 *
 */
public class BeverageTestDrive {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		TeaWithHook teaHook = new TeaWithHook();
		CoffeeWithHook coffeeHook = new CoffeeWithHook();
		
		System.out.println("\nMaking tea...");
		teaHook.prepareRecipe();
		
		System.out.println("\nMaking coffee...");
		coffeeHook.prepareRecipe();
	}

}

4. 输出:

Making tea...
Boiling water
Steeping the tea
Pouring into cup
Would you like lemon with your tea (y/n)? 
y
Adding Lemon

Making coffee...
Boiling water
Dripping Coffee through filter
Pouring into cup
Would you like milk and sugar with your coffee (y/n)? 
n