定义
定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
结构
AbstractClass 叫做抽象模板,它的方法分为两类:
● 基本方法
基本方法也叫做基本操作,是由子类实现的方法,并且在模板方法被调用,包含以下几种类型:
- 抽象方法:在抽象类中声明,由具体子类实现。
- 具体方法:在抽象类中已经实现,在具体子类中可以继承或重写它。
- 钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。
● 模板方法
可以有一个或几个,一般是一个具体方法,也就是一个框架,实现对基本方法的调度,完成固定的逻辑。
注意: 为了防止恶意的操作,一般模板方法都加上 final 关键字,不允许被覆写。
具体模板:ConcreteClass1 和 ConcreteClass2 属于具体模板,实现父类所定义的一个或多个抽象方法,也就是父类定义的基本方法在子类中得以实现
使用场景:
● 多个子类有公有的方法,并且逻辑基本相同时。
● 重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现。
● 重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数(见“模板方法模式的扩展”)约束其行为。
类图
案例
//不同年级学习
public abstract class Learn {
String name;
/**
* 早读
*/
abstract void earlyReading();
/**
* 上课
*/
abstract void beginClass();
/**
* 眼保健操
*/
void eyeExercises(String name){
System.out.println( name + "做眼保健操");
}
/**
* 通用的学校学校流程
*/
public final void learn(){
earlyReading();
beginClass();
eyeExercises(name);
}
public void setName(String name) {
this.name = name;
}
}
public class Kindergarten extends Learn {
Kindergarten(){
super.name = "幼儿园";
}
@Override
void earlyReading() {
System.out.println(name + "早读");
}
@Override
void beginClass() {
System.out.println(name + "上课学习唱歌");
}
}
public class PrimarySchool extends Learn {
PrimarySchool(){
super.name = "小学";
}
@Override
void earlyReading() {
System.out.println(name + "早读");
}
@Override
void beginClass() {
System.out.println(name + "上语文课、数学课、画画");
}
}
public class Demo {
public static void main(String[] args) {
Learn kindergarten = new Kindergarten();
kindergarten.learn();
System.out.println();
Learn school = new PrimarySchool();
school.learn();
}
}
//输出
幼儿园早读
幼儿园上课学习唱歌
幼儿园做眼保健操
小学早读
小学上语文课、数学课、画画
小学做眼保健操
总结
该模式的主要优点如下。
- 它封装了不变部分,扩展可变部分。它把认为是不变部分的算法封装到父类中实现,而把可变部分算法由子类继承实现,便于子类继续扩展。
- 它在父类中提取了公共的部分代码,便于代码复用。
- 部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能,符合开闭原则。
该模式的主要缺点如下。
- 对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象,间接地增加了系统实现的复杂度。
- 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。
- 由于继承关系自身的缺点,如果父类添加新的抽象方法,则所有子类都要改一遍。
NEXT
下次会对行为型模式-策略模式进行分析,欢迎点赞、关注、收藏,谢谢。
读书百遍,其义自见。我是二十三月,下次见。