行为型模式(Behavioral Pattern)是对不同的对象之间划分责任和算法的抽象化。行为型模式包括11种模式:模板方法模式、命令模式、责任链模式、策略模式、迭代器模式、中介者模式、观察者模式、备忘录模式、访问者模式、状态模式、解释器模式。
定义
模板方法模式(Template Method Pattern)是一种简单的、常见的且应用非常广泛的模式。
模板方法模式的英文原话是:Define the skeleton of an algorithm in an operation,deferring some steps to subclasses.Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.
翻译:定义一个操作中的算法框架,将一些步骤延迟到子类中,使得子类可以在不改变算法结构的前提下即可重新定义该算法的某些特定步骤。
角色:
抽象模板(Abstract Template)角色:该角色定义一个或多个抽象操作,以便让子类实现。这些抽象操作是基本操作,是一个顶级逻辑的组成步骤。还需要定义并实现一个或几个模板方法,这些模板方法一般是具体方法,即一个框架,实现对基本方法的调度,完成固定的逻辑。
具体模板(Concrete Template)角色:该角色实现抽象模板中定义的一个或多个抽象方法,每一个抽象模板角色都可以有任意多个具体模板角色与之对应,而每一个具体模板角色都可以给出这些抽象方法的不同实现,从而使得顶级逻辑的实现各不相同。
/** * 抽象模板角色 */ public abstract class AbstractClass { //基本方法 protected abstract void operation(); //基本方法2 protected abstract void operation2(); //模板方法 public void templateMethod(){ //调用基本方法,完成相关逻辑 this.operation(); this.operation2(); } } /** * 具体模板角色 */ public class ConcreteClass extends AbstractClass{ //实现基本业务方法 @Override protected void operation() { //业务逻辑 System.out.println("具体类的操作"); } @Override protected void operation2() { //业务逻辑 System.out.println("具体类的操作2"); } } public class Client { public static void main(String[] args) { AbstractClass ac = new ConcreteClass(); //调用模板方法 ac.templateMethod(); } }
源码
模板方法调用基本方法后结果如下:
优点
封装不变的部分,扩展可变的部分。将不变的部分封装到父类中实现,而可变的部分则可以通过继承进行扩展。
提取公共部分代码,便于维护。将公共部分的代码抽取出来放在父类中,维护时只需修改父类中的代码。
行为由父类控制,子类实现。模板方法模式中的基本方法是由子类实现的,因此子类可以通过扩展增加相应的功能,符合开闭原则。
应用场景
多个子类有公共方法,并且逻辑基本相同时。
可以把重要的、复杂的核心算法设计为模板方法,周边的相关细节功能则由各个子类实现。
重构时,模板方法模式是一种经常使用的模式,将相同的代码抽取出来放到父类中。
事务就用到了这个设计模式,前置增强,后置增强都延迟到子类中去。
计算银行利息Demo
/** * 抽象模板,抽象账户类 */ public abstract class Account { //账号 private String accountNumber; //构造函数 public Account(){ accountNumber = null; } public Account(String accountNumber) { this.accountNumber = accountNumber; } /** * 基本方法,确定账户类型,留给子类实现 * @return */ protected abstract String getAccountType(); /** * 基本方法,确定利息,留给子类实现 * @return */ protected abstract double getInterestRate(); /** * 基本方法,根据账户类型和账户确定账户金额 * @param accountType * @param accountNumber * @return */ public double calculateAmount(String accountType,String accountNumber){ //访问数据库...此处直接返回账户金额 return 10000.00D; } //模板方法,计算账户利息 public double calculateInterest(){ String accountType = getAccountType(); double interestRate = getInterestRate(); double amount = calculateAmount(accountType,accountNumber); return amount*interestRate; } } /** * 具体模板类,活期账户 */ public class DemandAccount extends Account { @Override protected String getAccountType() { return "活期"; } @Override protected double getInterestRate() { return 0.003D; } } /** * 具体模板类,定期账户 */ public class FixedAccount extends Account { /** * 基本方法,确定账户类型 * @return */ protected String getAccountType() { return "一年定期"; } /** * 基本方法,确定利息 * @return */ protected double getInterestRate() { return 0.04D; } } /** * 测试类 */ public class ClientAccount { public static void main(String[] args) { Account account = new DemandAccount(); System.out.println("活期账户利息:"+account.calculateInterest()); account = new FixedAccount(); System.out.println("一年定期账户利息:"+account.calculateInterest()); } }
源码
运行结果: