封装不变,扩展可变——模版方法模式
1. 前言
在平时的项目开发中,我们常会碰到这样的需求。整个业务流程可以由若干操作完成,其中某些操作对所有客户都一样,是不变的,而有些操作确需要由客户端决定,是经常会改变的。比如事务操作,流程可以定义为:
1.开启事务
2.对数据库进行操作
3.成功则提交事务否则回滚
在这个事务操作流程中,1和3是不变的,而2需要由客户端决定,对数据库进行什么样的操作。又比如常见的jdbc操作,流程可以定义为:
1.获取数据库连接
2.通过连接操作数据库
3.释放连接
在这里,2和3是不变的,而1需要由客户端决定获取mysql还是oracle还是其他什么连接。
那么这么时候,我们就可以使用模版方法模式。
2. 模版方法模式详解
2.1 定义
模版方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模版方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
2.2 类结构
2.3 使用场景
- 当多个子类业务处理流程基本类似且只有某些处理步骤不一样时,可以将业务流程定义在父类的模版方法中,模版方法中可以包含实例方法和抽象方法,实例方法代表所有子类都一样的操作步骤,定义在父类中且由父类实现;抽象方法表示子类各不相同的处理步骤,父类定义但是由子类实现。
- 重构代码的时候经常会用到,代码复用。
2.4 优点和缺点
-
优点
体现了“封装不变,扩展可变”的设计思想,符合开闭原则,有利于我们维护代码和对功能进行扩展。 -
缺点
行为由父类控制,但由子类实现,子类会影响父类结果,类层次结构复杂时会影响代码阅读。
2.5 简单实现
- 抽象模版类
该类有一个final修饰的模版方法,模版方法由三个方法组成,除了step2由自身实现外,step1和step3都由继承该类的子类实现
public abstract class AbstractClass {
//步骤一,父类定义,子类实现
protected abstract void step1();
//步骤二,父类实现
public void step2(){
System.out.println("AbstractClass:step2");
}
//步骤三,父类定义,子类实现
public abstract void step3();
public final void templateMethod(){
step1();
step2();
step3();
}
}
- 子类1
public class ConcreteClass1 extends AbstractClass {
@Override
protected void step1() {
System.out.println("ConcreteClass1:step1");
}
@Override
public void step3() {
System.out.println("ConcreteClass1:step3");
}
}
- 子类2
public class ConcreteClass2 extends AbstractClass {
@Override
protected void step1() {
System.out.println("ConcreteClass2:step1");
}
@Override
public void step3() {
System.out.println("ConcreteClass2:step3");
}
}
- 测试
public class TestCase {
public static void main(String[] args) {
AbstractClass c1=new ConcreteClass1();
AbstractClass c2=new ConcreteClass2();
c1.templateMethod();
System.out.println("-------------------------------------");
c2.templateMethod();
}
}
- 结果如下
参考资料:
- 《设计模式之禅》
- 《head First 设计模式》