模板方法模式——Template Method Pattern

本文介绍模板方法模式在冲泡饮料的应用案例,通过定义算法骨架,允许子类重新定义某些步骤而不改变整体流程。展示了如何使用抽象方法、具体方法和钩子方法实现灵活的设计。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

模板方法模式
模拟制作饮料的应用:
冲泡饮料时,我们需要遵循下面的冲泡步骤,即
(1)把水煮沸
(2)用沸水冲泡
(3)把冲泡后的饮料倒进杯子
(4)加入适当的调料

另外,对于不同的饮料,步骤(2)冲泡方法和步骤(4)的加入调料的方法是不同的
因此需要这两个方法设计为抽象方法,代码如下:
public abstract class Beverage
{
	void boilWater()
	{
		System.out.println("Boiling water.");
	}								//(1)把水煮沸
	void pourInCup()
	{
		System.out.println("Pouring into cup.")
	}								//(3)把饮料倒进杯子
	abstract void brew();			//(2)用沸水冲泡
	abstract void addCondiments();	//(4)加入适当的调料
}
我们有两种饮料需要使用这个冲泡饮料的方法,茶和咖啡,代码如下:
public class Tea extends Beverage
{
	public void brew()
	{
		System.out.println("Steeping the tea.");
	}//浸泡茶叶
	public void addCondiments()
	{
		System.out.println("Adding Lemon.");
	}//加入柠檬
}
public class Coffee extends Beverage
{
	public void brew()
	{
		System.out.println("Dripping Coffee through filter.");
	}//冲泡咖啡
	public void addCondiments()
	{
		System.out.println("Adding Sugar and Milk.");
	}//加入糖和牛奶
}
现在我们可以来制作茶和咖啡了,代码如下:
public class MarkBeverage
{
	Tea tea = new Tea();
	tea.boilWater();
	tea.brew();
	tea.pourInCup();
	tea.addCondiments();
	Coffee coffee = new Coffee();
	coffee.boilWater();
	coffee.brew();
	coffee.pourInCup();
	coffee.addCondiments();
}
一切看起来都很正常,可是,如果要新建多个对象,那么我们就要写多个方法调用
为了解决这个问题,我们可以将制作饮料的四个步骤写在一个方法里面,代码如下:

public abstract class Beverage
{
	void make()
	{
		boilWater();		//(1)把水煮沸
		brew();				//(2)用沸水冲泡
		pourInCup();		//(3)把饮料倒进杯子
		addCondiments();	//(4)加入适当的调料
	}
	void boilWater()
	{
		System.out.println("Boiling water.");
	}								//(1)把水煮沸
	void pourInCup()
	{
		System.out.println("Pouring into cup.")
	}								//(3)把饮料倒进杯子
	abstract void brew();			//(2)用沸水冲泡
	abstract void addCondiments();	//(4)加入适当的调料
}
这样做看起来清晰多了,使用时也变得相对简单,而且也达到了封装的效果:
public class MarkBeverage
{
	Tea tea = new Tea();
	tea.mark();
	Coffee coffee = new Coffee();
	coffee.mark();
}
这就是模板方法模式
模板方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中
                         子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤
代码演示:

public abstract class AbstractClass
{
	final void templateMethod
	{
		methodOne();
		methodTwo();
		/*------第N个普通方法------*/  
		abstractMethodOne();
		abstractMethodTwo();
		/*------第N个抽象方法------*/  
	}
	//不需要改变的步骤使用final声明
	final void methodOne(){}
	final void methodTwo(){}
	//可改变的步骤声明为抽象方法,在子类里重新定义
	abstract abstractMethodOne();
	abstract abstractMethodTwo();
}
另外,需要考虑到其它的一些情况,如,并不是所有人都会喝加牛奶的咖啡
那么,上例中的第个四步骤并不是必须的,这时我们就要加入一个判断语句:

public abstract class Beverage
{
	void make()
	{
		boilWater();			//(1)把水煮沸
		brew();					//(2)用沸水冲泡
		pourInCup();			//(3)把饮料倒进杯子
		if(isCustomerWantsCondiments())
		{
			addCondiments();	//(4)加入适当的调料
		}
	}
	void boilWater()
	{
		System.out.println("Boiling water.");
	}								//(1)把水煮沸
	void pourInCup()
	{
		System.out.println("Pouring into cup.")
	}								//(3)把饮料倒进杯子
	boolean isCustomerWantsCondiments()
	{
		return true;
	}//新加入的方法,用于判断是否加调料
	abstract void brew();			//(2)用沸水冲泡
	abstract void addCondiments();	//(4)加入适当的调料
}
现在我们知道了并不总是使用模板方法中的所有方法
为了解决这个问题,我们需要对模板方法进行挂钩,即使用钩子方法
上例中的isCustomerWantsCondiments()就是一个钩子
Swing窗体实例:
//此处省略import语句
public class MyFrame extends JFrame
{
	//update()方法为模板方法Template method
	public MyFrame(String title)
	{
		super(title);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setSize(300,300);
	}//初始化窗体
	public void paint(Graphics graphics)
	{
		super.paint(graphics);
		graphics.drawString("Hello",100,100);
	}//paint()方法为钩子方法Hook method
	public static void main(String args[])
	{
		MyFrame frame = new MyFrame("Hello!"); 
	}
}

模板方法定义了算法的步骤,并把这些步骤的实现延迟到子类
模板方法的抽象类可以定义具体方法,抽象方法和钩子方法
抽象方法是可变步骤,由子类实现
钩子方法可以控制某些步骤是否需要执行
模板方法用于封装算法并实现代码的复用


参考书籍《Head First 设计模式》














评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值