模板方法模式
模板方法模式是一种行为型设计模式,它定义了一个算法的骨架,将一些步骤延迟到子类中实现。这种模式允许子类在不改变算法结构的情况下重新定义算法的某些步骤。
结构
-
抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。其中包含了一些基本操作的步骤,有些步骤由具体子类实现。
-
模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
-
基本方法:是实现算法各个步骤的方法,是模板方法的组成部分。基本方法又可以分为三种:
-
抽象方法(Abstract Method) :一个抽象方法由抽象类声明、由其具体子类实现。
-
具体方法(Concrete Method) :一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承。
-
钩子方法(Hook Method) :在抽象类中已经实现,包括用于判断的逻辑方法 和需要子类重写的空方法两种。
一般钩子方法是用于判断的逻辑方法,这类方法名一般为isXxx,返回值类型为boolean类型。
-
-
-
具体子类(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的组成步骤。
案例:
你制作一个饮料,步骤是确定的,像烧水; 酿造;倒入杯中,添加调味品。烧水和倒杯是固定的基本操作,酿造和添加调味料这个则是通过具体的情况来定的。
代码实现:
java
// 抽象类
abstract class Beverage {
// 模板方法,定义了算法的骨架
public final void prepareBeverage() {
boilWater();
brew();
pourInCup();
addCondiments();
}
// 抽象方法,由子类实现
abstract void brew();
abstract void addCondiments();
// 公共方法,由父类实现
void boilWater() {
System.out.println("Boiling water");
}
void pourInCup() {
System.out.println("Pouring into cup");
}
}
// 具体类1
class Coffee extends Beverage {
@Override
void brew() {
System.out.println("Dripping coffee through filter");
}
@Override
void addCondiments() {
System.out.println("Adding sugar and milk");
}
}
// 具体类2
class Tea extends Beverage {
@Override
void brew() {
System.out.println("Steeping the tea");
}
@Override
void addCondiments() {
System.out.println("Adding lemon");
}
}
// 使用示例
public class Main {
public static void main(String[] args) {
Beverage coffee = new Coffee();
coffee.prepareBeverage();
System.out.println();
Beverage tea = new Tea();
tea.prepareBeverage();
}
}
注意:为防止恶意操作,一般模板方法都加上 final 关键词。
使用场景:
- 当有一系列算法步骤,其中有一部分是固定的,但是另一部分需要在子类中具体实现时,可以考虑使用模板方法模式。
- 当需要在不同的子类中重用相同的算法框架时,可以使用模板方法模式。
以下是模板方法模式在开发后台管理系统中的使用场景示例:
- 权限管理: 在后台管理系统中,通常需要对不同用户或用户组的权限进行管理。模板方法模式可以定义一个权限管理的骨架,包括权限验证、权限分配等操作,而具体的权限验证和分配操作可以交由子类实现。
- 数据的增删改查: 后台管理系统通常需要对数据进行增加、删除、修改、查询等操作。可以使用模板方法模式定义一个数据操作的骨架,包括数据的验证、数据的持久化等步骤,而具体的数据操作可以由子类实现。
- 数据的导入导出: 后台管理系统可能需要支持数据的导入导出功能,例如从 Excel 文件中导入数据到数据库,或者将数据库中的数据导出为 Excel 文件。可以使用模板方法模式定义一个数据导入导出的骨架,包括数据格式的验证、数据的转换等步骤,而具体的导入导出操作可以由子类实现。
- 日志记录: 后台管理系统通常需要记录用户的操作日志,例如登录日志、操作日志等。可以使用模板方法模式定义一个日志记录的骨架,包括日志的格式化、日志的存储等步骤,而具体的日志记录操作可以由子类实现。
优缺点:
优点:
-
提高代码复用性
将相同部分的代码放在抽象的父类中,而将不同的代码放入不同的子类中。
-
实现了反向控制
通过一个父类调用其子类的操作,通过对子类的具体实现扩展不同的行为,实现了反向控制 ,并符合"开闭原则"。
缺点:
- 对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象。
- 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。