设计模式之模版方法模式
设计模式之模版方法模式
定义
模版方法模式是编程中经常用得到的模式。它定义了一个操作中的算法骨架,将某些步骤延迟到子类中实现。这样,新的子类可以在不改变一个算法结构的前提下重新定义该算法的某些特定步骤。
通俗点的理解就是 :完成一件事情,有固定的数个步骤,但是每个步骤根据对象的不同,而实现细节不同;就可以在父类中定义一个完成该事情的总方法,按照完成事件需要的步骤去调用其每个步骤的实现方法。每个步骤的具体实现,由子类完成。
核心
处理某个流程的代码已经都具备,但是其中某个节点的代码暂时不能确定。因此,我们采用工厂方法模式,将这个节点的代码实现转移给子类完成,即:处理步骤父类中定义好,具体实现延迟到子类中定义
角色分类
抽象父类(AbstractClass):定义了钩子方法和实现了模板方法,定义了算法的骨架。
(1)模版方法:由抽象类声明并加以实现。一般来说,模版方法调用抽象方法来完成主要的逻辑功能,并且,模版方法大多会定义为final类型,指明主要的逻辑功能在子类中不能被重写。
(2)钩子方法:由抽象类声明并加以实现。但是子类可以去扩展,子类可以通过扩展钩子方法来影响模版方法的逻辑。
抽象类的任务是搭建逻辑的框架,通常由经验丰富的人员编写,因为抽象类的好坏直接决定了程序是否稳定性。
实现类用来实现细节。抽象类中的模版方法正是通过实现类扩展的方法来完成业务逻辑。只要实现类中的扩展方法通过了单元测试,在模版方法正确的前提下,整体功能一般不会出现大的错误。
具体类(ConcreteClass):实现抽象类中的抽象方法(钩子方法),即不同的对象的具体实现细节。
例子:客户到银行办理业务
代码
/**
* 抽象父类
* @author mama
*
*/
public abstract class BankTemplateMethod {
// 具体方法
public void takeNumber() {
System.out.println("取号排队");
}
public abstract void transact(); // 办理具体的业务 //钩子方法
public void evaluate() {
System.out.println("反馈评分");
}
public final void process() { // 模板方法!!!
this.takeNumber();
this.transact();
this.evaluate();
}
}
/**
* 客户端
* @author mama
*
*/
public class Client {
public static void main(String[] args) {
BankTemplateMethod btm = new DrawMoney();
btm.process();
//采用匿名内部类的方式创建具体类
BankTemplateMethod btm2 = new BankTemplateMethod() {
@Override
public void transact() {
System.out.println("我要存钱!");
}
};
btm2.process();
BankTemplateMethod btm3 = new BankTemplateMethod() {
@Override
public void transact() {
System.out.println("我要理财!我这里有2000万韩币");
}
};
btm3.process();
}
}
/**
* 具体类
* @author mama
*
*/
class DrawMoney extends BankTemplateMethod {
@Override
public void transact() {
System.out.println("我要取款!!!");
}
}
结果
取号排队
我要取款!!!
反馈评分
取号排队
我要存钱!
反馈评分
取号排队
我要理财!我这里有2000万韩币
反馈评分
模版模式的优点
(1)容易扩展。一般来说,抽象类中的模版方法是不易反生改变的部分,而抽象方法是容易反生变化的部分,因此通过增加实现类一般可以很容易实现功能的扩展,符合开闭原则。
(2)便于维护。对于模版方法模式来说,正是由于他们的主要逻辑相同,才使用了模版方法,假如不使用模版方法,任由这些相同的代码散乱的分布在不同的类中,维护起来是非常不方便的。
模版模式的缺点
(1) 比较灵活。因为有钩子方法,因此,子类的实现也可以影响父类中主逻辑的运行。但是,在灵活的同时,由于子类影响到了父类,违反了里氏替换原则,也会给程序带来风险。这就对抽象类的设计有了更高的要求。
(2) 每个不同的实现都需要定义一个子类,会导致类的个数增加,系统更加庞大。
适用场景
(1)实现一个算法时,整体步骤很固定,但是,某些部分易变。易变部分可以抽象出来。供子类实现。
(2) 在多个子类拥有相同的方法,并且这些方法逻辑相同时,可以考虑使用模版方法模式。在程序的主框架相同,细节不同的场合下,也比较适合使用这种模式。
开发中常见的场景
(1)数据库访问的封装
(2)Junit单元测试
(3)Servlet中关于diGet/doPost方法调用
(4)Hibernate中的模版程序
(5)Spring中JDBCTemplate,HibernateTemplate等