目录
1 模板方法模式介绍
模板方法模式(template method pattern)原始定义是:在操作中定义算法的框架,将一些步骤推迟到子类中。模板方法让子类在不改变算法结构的情况下重新定义算法的某些步骤。
模板方法的作用主要是提高程序的复用性和扩展性:
- 复用指的是,所有的子类可以复用父类中提供的模板方法代码
- 扩展指的是,框架通过模板模式提供功能扩展点,让框架用户可以在不修改框架源码的情况下,基于扩展点定制化框架的功能.
2 模板方法模式原理
模板方法(Template Method)模式包含以下主要角色:
- 抽象父类:定义一个算法所包含的所有步骤,并提供一些通用的方法逻辑。
- 具体子类:继承自抽象父类,根据需要重写父类提供的算法步骤中的某些步骤。
抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。
-
模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
-
基本方法:是实现算法各个步骤的方法,是模板方法的组成部分。基本方法又可以分为三种:
-
抽象方法(Abstract Method) :一个抽象方法由抽象类声明、由其具体子类实现。
-
具体方法(Concrete Method) :一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承。
-
钩子方法(Hook Method) :在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。
一般钩子方法是用于判断的逻辑方法,这类方法名一般为isXxx,返回值类型为boolean类型。
-
3 模板方法模式实现
/**
* 抽象父类
* @author spikeCong
* @date 2022/10/12
**/
public abstract class AbstractClassTemplate {
void step1(String key){
System.out.println("在模板类中 -> 执行步骤1");
if(step2(key)){
step3();
}else{
step4();
}
step5();
}
boolean step2(String key){
System.out.println("在模板类中 -> 执行步骤2");
if("x".equals(key)){
return true;
}
return false;
}
abstract void step3();
abstract void step4();
void step5(){
System.out.println("在模板类中 -> 执行步骤5");
}
void run(String key){
step1(key);
}
}
public class ConcreteClassA extends AbstractClassTemplate{
@Override
void step3() {
System.out.println("在子类A中 -> 执行步骤 3");
}
@Override
void step4() {
System.out.println("在子类A中 -> 执行步骤 4");
}
}
public class ConcreteClassB extends AbstractClassTemplate {
@Override
void step3() {
System.out.println("在子类B中 -> 执行步骤 3");
}
@Override
void step4() {
System.out.println("在子类B中 -> 执行步骤 4");
}
}
public class Test01 {
public static void main(String[] args) {
AbstractClassTemplate concreteClassA = new ConcreteClassA();
concreteClassA.run("");
System.out.println("===========");
AbstractClassTemplate concreteClassB = new ConcreteClassB();
concreteClassB.run("x");
}
}
// 输出结果
在模板类中 -> 执行步骤1
在模板类中 -> 执行步骤2
在子类A中 -> 执行步骤 4
在模板类中 -> 执行步骤5
===========
在模板类中 -> 执行步骤1
在模板类中 -> 执行步骤2
在子类B中 -> 执行步骤 3
在模板类中 -> 执行步骤5
4 模板方法模式应用实例
/**
* 账户抽象类
* @author spikeCong
* @date 2022/10/12
**/
public abstract class Account {
//step1 具体方法-验证用户信息是否正确
public boolean validate(String account,String password){
System.out.println("账号: " + account + ",密码: " + password);
if(account.equalsIgnoreCase("tom") &&
password.equalsIgnoreCase("123456")){
return true;
}else{
return false;
}
}
//step2 抽象方法-计算利息
public abstract void calculate();
//step3 具体方法-显示利息
public void display(){
System.out.println("显示利息!");
}
//模板方法
public void handle(String account,String password){
if(!validate(account,password)){
System.out.println("账户或密码错误!!");
return;
}
calculate();
display();
}
}
/**
* 借款一个月
* @author spikeCong
* @date 2022/10/12
**/
public class LoanOneMonth extends Account{
@Override
public void calculate() {
System.out.println("借款周期30天,利率为10%!");
}
}
/**
* 借款七天
* @author spikeCong
* @date 2022/10/12
**/
public class LoanSevenDays extends Account{
@Override
public void calculate() {
System.out.println("借款周期7天,无利息!仅收取贷款金额1%的服务费!");
}
@Override
public void display() {
System.out.println("七日内借款无利息!");
}
}
public class Client {
public static void main(String[] args) {
Account a1 = new LoanSevenDays();
a1.handle("tom","12345");
System.out.println("==========================");
Account a2 = new LoanOneMonth();
a2.handle("tom","123456");
}
}
5 模板方法模式总结
优点:
-
在父类中形式化的定义一个算法,而由它的子类来实现细节处理,在子类实现详细的处理代码时,并不会改变父类算法中步骤的执行顺序.
-
模板方法可以实现一种反向的控制结构,通过子类覆盖父类的钩子方法,来决定某一个特定步骤是否需要执行
-
在模板方法模式中可以通过子类来覆盖父类的基本方法,不同的子类可以提供基本方法的不同实现,更换和增加新的子类很方便,符合单一职责原则和开闭原则.
缺点:
- 对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象。
- 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。
模板方法模式的使用场景一般有:
- 多个类有相同的方法并且逻辑可以共用时;
- 将通用的算法或固定流程设计为模板,在每一个具体的子类中再继续优化算法步骤或流程步骤时;
- 重构超长代码时,发现某一个经常使用的公有方法。