原来在项目中重构过一次代码,当时还很菜,一共搞了两个多星期吧。天天想着重构,想的脑子都要大了。然后,师父说让看看模版方法模式,然后就看了。模版方法模式是什么?举个例子,生活中有很多都是模版的例子,我们提到模版最多的地方应该就是英语/语文作文了。英语作文模版怎么说的来着。
第一段:引出论点。
中间段:相反/我认为或者在我的观点中,巴拉巴拉
第三段:总结陈词。
第一和第三段的句式大体相同,只有中间的论点不一样。这就是生活中常见的模版方法模式。
模版方法模式就是算法执行的统一框架,其中大体结构是相同的,而具体实现由不同的子类来决定。
Step1
...
Step2
...
Stepn
其中Step1,Stepn相同,Step2不同。
模版定义了一个操作中的算法骨架,将一些步骤延迟到子类实现,使得子类可以在不改变一个算法结构的同时重新定义一个算法的特定步骤。
下面以java实现用代码具体介绍,我们给出泡茶和泡咖啡的例子。
饮料的调制方法
咖啡的泡发 茶的泡法
1.把水煮沸 1.把水煮沸
2.用沸水冲泡咖啡 2.用沸水侵泡茶叶
3.把咖啡倒进杯子 3.把茶倒进杯子
4.加糖和牛奶 4.不加东西
可以看出,除了2,4步不一样之外,其他的步骤都是一样的,因此,我们可以提取出模版
1.把水煮沸 boilWater
2.泡饮料 brew
3.把饮料倒进杯子pourIncup
4.加调味料 addCondiments
我们来新建一个父类模版类,它是一个抽象类,含有上面的所有方法,包括基本方法和抽象的基本方法。以及调用所有方法的整个模版方法。
/*
* 抽象基类,为所有子类提供一个算法框架
*
* 提神饮料
*/
public abstract class RefreshBeverage {
/*
* 制备饮料的模版方法 封装了所有子类共同遵循的算法框架
*/
// 一定要要用final,阻止子类覆写
public final void prepareBeverageTemplate() {
// 步骤1 将水煮沸
boilWater();
// 步骤2 泡制饮料
brew();
// 步骤3 将饮料倒入水中
pourInCup();
if (isCustomerWantsCondiments()) {
// 步骤4 加入调味料
addCondiments();
}
}
/*
* Hook,钩子函数,提供一个默认或空的实现
* 具体的子类可以自行决定是否挂钩以及如何挂钩
* 询问用户是否加入调料
*/
protected boolean isCustomerWantsCondiments() {
// TODO Auto-generated method stub
return true;
}
/*
* 抽象的基本方法,加入调味料
*/
protected abstract void addCondiments();
/*
* 基本方法,将饮料倒入水中
*/
private void pourInCup() {
System.out.println("倒入杯中");
}
/*
* 抽象的基本方法,泡制饮料
*/
protected abstract void brew();
/*
* 基本方法,将水煮沸
*/
private void boilWater() {
System.out.println("将水煮沸");
}
}
下面是其中Coffee子类
/*
* 具体子类,提供了咖啡制作的条件
*/
public class Coffee extends RefreshBeverage{
@Override
protected void addCondiments() {
// TODO Auto-generated method stub
System.out.println("用沸水冲泡咖啡");
}
@Override
protected void brew() {
// TODO Auto-generated method stub
System.out.println("添加糖和牛奶");
}
}
下面是茶的子类
public class Tea extends RefreshBeverage {
@Override
protected void addCondiments() {
System.out.println("加入柠檬");
}
@Override
protected void brew() {
System.out.println("用80度的热水浸泡茶叶5分钟");
}
/**
* 子类选择覆盖的形式选择挂载钩子函数
*/
protected boolean isCustomerWantsCondiments() {
return false;
}
}
我们编写一个测试函数来运行一下
public static void main(String[] args) {
System.out.println("制备咖啡");
RefreshBeverage b1=new Coffee();
b1.prepareBeverageTemplate();
System.out.println("咖啡好了");
System.out.println("\n***************");
System.out.println("制备茶");
RefreshBeverage b2=new Tea();
b2.prepareBeverageTemplate();
System.out.println("茶好了");
}
}
结果如下:
制备咖啡
将水煮沸
添加糖和牛奶
倒入杯中
用沸水冲泡咖啡
咖啡好了
***************
制备茶
将水煮沸
用80度的热水浸泡茶叶5分钟
倒入杯中
茶好了
ok,这就是模版方法模式。
模版方法有两点因素:抽象基类和具体子类,其中抽象基类中有一个final模版方法,子类要实现基类的抽象方法,将部分逻辑以具体方法的形式实现
使用场景:
1.算法或操作遵循相似的逻辑
2.重构时(把相同的代码抽取到父类中)
3.重要,复杂的算法,核心算法设计为模版算法
总结一下模版方法模式的优缺点
优点:
1.封装性好 2,复用性好 3.屏蔽细节 4.便于维护
缺点:
使用了继承