一、什么是模板模式
模板模式通过一个抽象类来定义需要实现的框架,通过一系列的抽象方法,将方法延迟到子类去实现。相当于对一个程序建立一套模板,子类可以根据自身需要,按照模板的要求进行功能上的填充和扩展。
二、案例
1.如果我们想炒一道菜,可以用抽象类定义好一系列的模板方法,如加盐–>爆炒–>上菜:
abstract class Cook{
protected abstract void name(); //定义炒菜的模板方法
protected abstract void salt();
protected abstract void cook();
protected abstract void finish();
public void letsCook(){
System.out.println("开始炒菜");
this.name();
this.salt();
this.cook();
this.finish();
System.out.println("结束");
}
}
2.创建一个子类,表示做红烧肉,继承模板类,并根据自身需要实现做红烧肉的方法:
class HongShaoRou extends Cook{
@Override
void name() {
System.out.println("做红烧肉");
}
@Override
void salt() {
System.out.println("加10g盐"); //红烧肉做加点盐
}
@Override
void cook() {
System.out.println("爆炒10分钟"); //爆炒一下
}
@Override
void finish() {
System.out.println("起锅");
}
}
3.创建另一个子类,表示做鸡蛋汤,继承模板类,并提供做鸡蛋汤的方法:
class EggSoup extends Cook{
@Override
void name() {
System.out.println("做鸡蛋汤");
}
@Override
void salt() {
System.out.println("加2g盐"); //汤可以少加盐
}
@Override
void cook() {
System.out.println("煮5分钟"); //煮一会儿就可以出锅
}
@Override
void finish() {
System.out.println("起锅");
}
}
4.客户类,通过多态调用抽象类的模板方法:
public class Template {
public static void main(String[] args) {
Cook hongShaoRou = new HongShaoRou();
hongShaoRou.letsCook();
System.out.println("===========================");
Cook eggSoup = new EggSoup();
eggSoup.letsCook();
}
}
5.执行结果:
开始炒菜
做红烧肉
加10g盐
爆炒10分钟
起锅
结束
===========================
开始炒菜
做鸡蛋汤
加2g盐
煮5分钟
起锅
结束
三、总结
上面的案例我们通过定义一个炒菜的抽象类,规定一系列需要执行的模板方法,最后再在其子类中延迟实现模板方法,就可以实现各类菜品都按照炒菜的流程走,但每个菜品的实现细节又有所不同,这就是模板模式的特点。
模板模式优缺点(参考:https://juejin.im/post/6844903689103081479):
优点:
- 在父类中形式化地定义一个算法,而由它的子类来实现细节的处理,在子类实现详细的处理算法时并不会改变算法中步骤的执行次序。
- 模板方法模式是一种代码复用技术,它在类库设计中尤为重要,它提取了类库中的公共行为,将公共行为放在父类中,而通过其子类来实现不同的行为,它鼓励我们恰当使用继承来实现代码复用。
- 可实现一种反向控制结构,通过子类覆盖父类的钩子方法来决定某一特定步骤是否需要执行。
- 在模板方法模式中可以通过子类来覆盖父类的基本方法,不同的子类可以提供基本方法的不同实现,更换和增加新的子类很方便,符合单一职责原则和开闭原则。
缺点:
- 需要为每一个基本方法的不同实现提供一个子类,如果父类中可变的基本方法太多,将会导致类的个数增加,系统更加庞大,设计也更加抽象,此时,可结合桥接模式来进行设计。
应用:
在并发包中AQS类(AbstractQueuedSynchronizer)中,里面的tryAcquire、tryRelease方法就是一个模板方法,需要由子类继承实现: