模板方法模式
模拟制作饮料的应用:
在冲泡饮料时,我们需要遵循下面的冲泡步骤,即
(1)把水煮沸
(2)用沸水冲泡
(3)把冲泡后的饮料倒进杯子
(4)加入适当的调料
另外,对于不同的饮料,步骤(2)的冲泡方法和步骤(4)的加入调料的方法是不同的
因此需要将这两个方法设计为抽象方法,代码如下:
为了解决这个问题,我们可以将制作饮料的四个步骤写在一个方法里面,代码如下:
模板方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中
子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤
代码演示:
那么,上例中的第个四步骤并不是必须的,这时我们就要加入一个判断语句:
为了解决这个问题,我们需要对模板方法进行挂钩,即使用钩子方法
上例中的isCustomerWantsCondiments()就是一个钩子
Swing窗体实例:
模板方法定义了算法的步骤,并把这些步骤的实现延迟到子类
模板方法的抽象类可以定义具体方法,抽象方法和钩子方法
抽象方法是可变步骤,由子类实现
钩子方法可以控制某些步骤是否需要执行
模板方法用于封装算法并实现代码的复用
参考书籍《Head First 设计模式》
在冲泡饮料时,我们需要遵循下面的冲泡步骤,即
(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 设计模式》