设计模式之模版方法模式(Template)
一、模版方法模式介绍
1、模版方法模式定义:
模板方法模式(template method pattern)原始定义是:在操作中定义算法的框架,将一些
步骤推迟到子类中。模板方法让子类在不改变算法结构的情况下重新定义算法的某些步骤。
模板方法中的算法可以理解为广义上的业务逻辑,并不是特指某一个实际的算法。
定义中所说的算法的框架就是模板, 包含算法框架的方法就是模板方法。
模板方法模式是一种基于继承的代码复用技术,它是一种类行为模式。
模板方法模式其结构中只存在父类与子类之间的继承关系。
模板方法的作用主要是提高程序的复用性和扩展性:
1)复用指的是,所有的子类可以复用父类中提供的模板方法代码
2)扩展指的是,框架通过模板模式提供功能扩展点,让框架用户可以在不修改框架
源码的情况下,基于扩展点定制化框架的功能。
如: 我们去医院看病一般要经过以下4个流程:挂号、取号、排队、医生问诊等,其中挂
号、 取号 、排队对每个病人是一样的,可以在父类中实现,但是具体医生如何根据
病情开药每个人都是不一样的,所以开药这个操作可以延迟到子类中实现。
二、模版方法模式原理
1、模版方法模式角色
模板方法模式的定位很清楚,就是为了解决算法框架这类特定的问题,同时明确表示需要
使用继承的结构。
模版方法模式类图如下:
模版方法模式包含如下角色:
抽象父类:定义一个算法所包含的所有步骤,并提供一些通用的方法逻辑。
抽象父类:负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个
基本方法构成。
具体子类:继承自抽象父类,根据需要重写父类提供的算法步骤中的某些步骤。
模版方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
基本方法:是实现算法各个步骤的方法,是模板方法的组成部分。
基本方法又可以分为三种:
1)抽象方法(Abstract Method) :一个抽象方法由抽象类声明、由其具体子类实现。
2)具体方法(Concrete Method) :一个具体方法由一个抽象类或具体类声明并实现,
其子类可以进行覆盖也可以直接继承。
3)钩子方法(Hook Method) :在抽象类中已经实现,包括用于判断的逻辑方法和需
要子类重写的空方法两种。
一般钩子方法是用于判断的逻辑方法,这类方法名一般为isXxx,返回值类型为
boolean类型。
2、用代码表示模版方法模式,
代码如下:
*******************************************************
* 抽象父类
*
* @author lbf
*******************************************************/
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);
}
}
/*******************************************************
* 具体子类A
*
* @author lbf
*
*******************************************************/
public class ConcreteClassA extends AbstractClassTemplate{
@Override
void step3() {
System.out.println("在子类A中 -> 执行步骤 3");
}
@Override
void step4() {
System.out.println("在子类A中 -> 执行步骤 4");
}
}
/*******************************************************
* 具体子类B
*
* @author lbf
*******************************************************/
public class ConcreteClassB extends AbstractClassTemplate{
@Override
void step3() {
System.out.println("在子类B中 -> 执行步骤 3");
}
@Override
void step4() {
System.out.println("在子类B中 -> 执行步骤 4");
}
}
三、模版方法模式应用示例
以P2P公司的借款系统中有一个利息计算模块为例来看下模版方法模式的使用;
利息的计算流程是这样的:
1)用户登录系统,登录时需要输入账号密码,如果登录失败(比如用户密码错误),
系统需要给出提示
2)如果用户登录成功,则根据用户的借款的类型不同,使用不同的利息计算方式进
行计算,系统需要显示计算的利息。
示例代码如下:
/*******************************************************
* 账户类--抽象父类
*
* @author lbf
* @date 2024-11-06 22:14
*******************************************************/
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();
}
}
/*******************************************************
* 借款1个月--具体子类
* @author lbf
* @date 2024-11-06 22:15
*******************************************************/
public class LoanOneMonth extends Account{
@Override
public void calculate() {
System.out.println("借款周期30天,利率为10%!");
}
}
/*******************************************************
* 借款7天--具体子类
* @author lbf
* @date 2024-11-06 22:16
*******************************************************/
public class LoanSevenDays extends Account{
@Override
public void calculate() {
System.out.println("借款周期7天,无利息!仅收取贷款金额1%的服务费!");
}
@Override
public void display() {
System.out.println("七日内借款无利息!");
}
}
/*******************************************************
*
* @author lbf
* @date 2024-11-06 22:16
*******************************************************/
public class Test {
public static void main(String[] args) {
Account a1 = new LoanSevenDays();
a1.handle("tom","12345");
System.out.println("==========================");
Account a2 = new LoanOneMonth();
a2.handle("zhudy","123456789");
}
}
四、模版方法模式总结
1、模版方法模式优点
1)在父类中形式化的定义一个算法,而由它的子类来实现细节处理,在子类实现详细的
处理代码时,并不会改变父类算法中步骤的执行顺序
2)模板方法可以实现一种反向的控制结构,通过子类覆盖父类的钩子方法,来决定某一个
特定步骤是否需要执行
3)在模板方法模式中可以通过子类来覆盖父类的基本方法,不同的子类可以提供基本方法
的不同实现,更换和增加新的子类很方便,符合单一职责原则和开闭原则
2、模版方法模式缺点
1)对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,
设计也更加抽象
2)父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向
的控制结构,它提高了代码阅读的难度。
3、模版方法模式适用场景
1)多个类有相同的方法并且逻辑可以共用时;
2)将通用的算法(业务流程)或固定流程设计为模板,在每一个具体的子类中再继续
优化算法步骤或流程步骤时;
3)重构超长代码时,发现某一个经常使用的公有方法。