模板方法模式是准备一个抽象类,将部分逻辑以具体方法以及构造子的形式出现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑部分有不同的实现。这也是模板方法模式的用意。

  模板方法模式是基于继承的代码复用的基本技术。

1.  结构

  模板方法模式的静态结构如下:

涉及到的角色如下:

抽象模板角色(AbstractClass):其责任主要如下

(1)定义了一个或多个抽象操作,以便让子类实现。这些操作叫做基本操作,它们是一个顶级逻辑的组成步骤。

(2)定义并实现了一个模板方法。这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法。

具体模板(ConcretrClass)角色:其责任如下

(1)实现父类所定义的一个或多个抽象方法,它们是一个顶级逻辑的组成步骤。

(2)每一个抽象模板角色都可以有任意多个具体模板角色与之对应,而每一个具体模板角色都可以给出这些抽象方法的不同实现,从而使得顶级逻辑的实现各不相同。

代码如下:

package cn.qlq.teplate;

public abstract class AbstractClass {

    public void templateMethod() {
// 处理前 doOperation1(); doOperation2(); doOperation3(); // 处理后
} void doOperation1() {
System.out.println("doOperation1默认实现");
} abstract void doOperation2(); abstract void doOperation3(); }

  doOperation1(),doOperation2(),doOperation3()等基本方法是顶级逻辑的组成步骤。这个顶级逻辑由templateMethod方法代表。抽象类提供了doOperation1的默认实现,doOperation2和doOperation3交给子类去实现。

package cn.qlq.teplate;

public class ConcreteClass1 extends AbstractClass {

    @Override
void doOperation2() {
System.out.println("ConcreteClass1 doOperation2");
} @Override
void doOperation3() {
System.out.println("ConcreteClass1 doOperation3");
} }
package cn.qlq.teplate;

public class ConcreteClass2 extends AbstractClass {

    @Override
void doOperation1() {
System.out.println("ConcreteClass2 doOperation1");
} @Override
void doOperation2() {
System.out.println("ConcreteClass2 doOperation2");
} @Override
void doOperation3() {
System.out.println("ConcreteClass2 doOperation3");
} }

客户端代码:

package cn.qlq.teplate;

public class Client {

    public static void main(String[] args) {
AbstractClass abstractClass = new ConcreteClass2();
abstractClass.templateMethod();
} }

结果:

ConcreteClass2 doOperation1
ConcreteClass2 doOperation2
ConcreteClass2 doOperation3

2.  例子

  一个银行计息的例子。假设银行需要两种存款账号,货币市场账号(MoneyMarket)和定期(Certificate of Deposite)存款账号。这个系统的总行为是计算出利息,这也就决定了作为模板方法的顶级逻辑应当是利息计算。利息计算涉及两步:一是确定账号类型、二是确定利息的百分比。

结构图如下:

  模板方法模式的实现方法是从上向下的,也就是说需要先给出顶级的逻辑,然后给出具体步骤的逻辑。

代码如下:

package cn.qlq.template;

public abstract class Account {

    protected String accountNumber;

    public Account(String accountNumber) {
super();
this.accountNumber = accountNumber;
} public final double calculateInterest() {
double interestRate = doCalculateInterestRate();
String accountType = doCalculateAccountType();
double amount = doCalculateAmount(accountType, accountNumber); return amount * interestRate;
} abstract double doCalculateAmount(String accountType, String accountNumber2); abstract String doCalculateAccountType(); abstract double doCalculateInterestRate(); }
package cn.qlq.template;

public class CDAccount extends Account {

    public CDAccount(String accountNumber) {
super(accountNumber);
} @Override
double doCalculateAmount(String accountType, String accountNumber2) {
// 模拟从数据库查出数据
return 50D;
} @Override
String doCalculateAccountType() {
return "CDAccount";
} @Override
double doCalculateInterestRate() {
return 0.048D;
} }
package cn.qlq.template;

public class MoneyMarket extends Account {

    public MoneyMarket(String accountNumber) {
super(accountNumber);
} @Override
double doCalculateAmount(String accountType, String accountNumber2) {
// 模拟从数据库查出数据
return 50D;
} @Override
String doCalculateAccountType() {
return "Money Market";
} @Override
double doCalculateInterestRate() {
return 0.045D;
} }

客户端代码:

package cn.qlq.template;

public class Client {
public static void main(String[] args) {
Account account = new CDAccount("123");
double calculateInterest = account.calculateInterest();
System.out.println(calculateInterest); Account moneyMarket = new MoneyMarket("123");
double moneyMarketInterest = moneyMarket.calculateInterest();
System.out.println(moneyMarketInterest);
}
}

3.小结

1.继承作为复用的工具

(1)首先,初学Java的不知道什么是继承,或者认为继承是高深的工具。这样设计大部分的功能是通过委派进行的。

(2)慢慢的发现继承并不难,并且初步认识到继承可以使子类一下子得到父类的行为。于是试图将继承作为功能复用的主要工具,并把原来应当使用委派的地方改为使用继承,这时候就造成继承的滥用。

(3)设计中也提倡使用委派关系代替继承。比如状态模式、策略模式、装饰模式、桥梁模式等。

(4)事实上封装、继承、多态和抽象化并称为面向对象的特性。所以应当合理的使用继承。

2. Java语言的模板方法模式

HttpServlet技术就使用了模板方法模式。HttpServlet提供了一个service()方法,这个方法调用7个do方法中的一个或几个,完成对客户端调用的处理。

3.模板方法模式中的方法

  模板方法中的方法可以分为两类:模板方法和基本方法。

模板方法:

  一般是定义在抽象类中,把基本方法组合在一起形成一个总的方法或者行为的方法。这个方法一般定义在抽象类中并且由子类不加以修改地完全继承下来。

  一个抽象类可以有任意多个模板方法,而不限于一个。每一个模板方法都可以调用任意多个具体方法。

基本方法:

  基本方法又分为三种:抽象方法、具体方法和钩子方法

(1)抽象方法:由抽象类声明并由具体子类实现

(2)具体方法:由抽象类声明并实现,子类不实现或置换。有些具体方法可以起到工厂方法的作用,这样的具体方法又叫做工厂方法。

(3)钩子方法:一个钩子方法由抽象类声明并实现,而子类会加以扩展。通常抽象类给出的实现是一个空实现,作为方法的默认实现(在缺省适配器模式也见过)。

注意命名规则:

  钩子方法的名字应当以do开始,这是熟悉设计模式的Java程序设计师的标准做法。在HttpServlet中也遵循这一规则。

总结:

意图:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

主要解决:一些方法通用,却在每一个子类都重新写了这一方法。

何时使用:有一些通用的方法。

如何解决:将这些通用算法抽象出来。

关键代码:在抽象类实现,其他步骤在子类实现。

应用实例: 1、在造房子的时候,地基、走线、水管都一样,只有在建筑的后期才有加壁橱加栅栏等差异。 2、西游记里面菩萨定好的 81 难,这就是一个顶层的逻辑骨架。 3、spring 中对 Hibernate 的支持,将一些已经定好的方法封装起来,比如开启事务、获取 Session、关闭 Session 等,程序员不重复写那些已经规范好的代码,直接丢一个实体就可以保存。

优点: 1、封装不变部分,扩展可变部分。 2、提取公共代码,便于维护。 3、行为由父类控制,子类实现。

缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。

使用场景: 1、有多个子类共有的方法,且逻辑相同。 2、重要的、复杂的方法,可以考虑作为模板方法。

注意事项:为防止恶意操作,一般模板方法都加上 final 关键词

模板方法(TemplateMethod)模式的更多相关文章

  1. Java 实现模板方法(TemplateMethod)模式

    类图 /** * 业务流程模板.提供基本框架 * @author stone * */ public abstract class BaseTemplate { public abstract voi ...

  2. C#中的TemplateMethod模式

    一个真实的故事 大学的时候就开过一门课程,讲设计模式,可是大学生没什么编程实践经验,在大学里面听设计模式的感觉,就像听天书.听着都有道理,可是完全领会不到其中的奥妙,大抵原因就在于没有走过弯路,没有吃 ...

  3. Template Method(模板方法)模式

    1.概述 在面向对象开发过程中,通常我们会遇到这样的一个问题:我们知道一个算法所需的关键步骤,并确定了这些步骤的执行顺序.但是某些步骤的具体实现是未知的,或者说某些步骤的实现与具体的环境相关.例子1: ...

  4. 3.设计模式----TemplateMethod模式

    模板模式,其实是一种思想,在开发中有很多地方用到模板,因为毕竟我们不可能每一个都一出一段!一个模板,填充不同,出来效果也是不一样! 准备画个时序图的,没找到工具,过几天补上! 模板模式在出现bug时候 ...

  5. 【行为型】TemplateMethod模式

    模板方法意图是为算法定义好骨架结构,并且其中的某些步骤延迟到子类实现.该模式算是较为简单的一种设计模式.在实际中,应用也较为频繁.模式的类关系图参考如下: 模式的编码结构参考如下: namespace ...

  6. java设计模式(9):模板方法模式(TemplateMethod)

    一,定义:模板方法模式定义了一个操作中的算法骨架,而将一些步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 二,类图: 三,通过小例子讲解: 这个模式一般用在 ...

  7. C#设计模式系列:模板方法模式(Template Method)

    你去银行取款的时候,银行会给你一张取款单,这张取款单就是一个模板,它把公共的内容提取到模板中,只留下部分让用户来填写.在软件系统中,将多个类的共有内容提取到一个模板中的思想便是模板方法模式的思想. 模 ...

  8. C#设计模式之十四模板方法模式(Template Method)【行为型】

    一.引言 “结构型”的设计模式已经写完了,从今天我们开始讲“行为型”设计模式.现在我们开始讲[行为型]设计模式的第一个模式,该模式是[模板方法],英文名称是:Template Method Patte ...

  9. C#设计模式之十三模板方法模式(Template Method Pattern)【行为型】

    一.引言 “结构型”的设计模式已经写完了,从今天我们开始讲“行为型”设计模式.现在我们开始讲[行为型]设计模式的第一个模式,该模式是[模板方法],英文名称是:Template Method Patte ...

随机推荐

  1. es6中的arrowfunction

    es6新增箭头函数,主要解决了以下几点问题 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象. 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误. 不可以使用 ...

  2. javascript DOM拓展

    针对JS高级程序设计这本书,主要是理解概念,大部分要点源自书内.写这个主要是当个笔记加总结 存在的问题请大家多多指正! DOM拓展 1选择符 API 1.1 querySelector() 由docu ...

  3. SharePoint Rest Api Caml multiple condition query -Rest api 利用Caml多个条件查询

    $.ajax({ var cquery="<View><Query><Where><And><Geq><FieldRef N ...

  4. 开关VoLTE流程分析(二)

    AT指令,暂未发现发送AT请求的frameworks接口,通过打印信息总结AT指令: AT+EIMSVOICE: Enable/Disable IMS Voice Capability+EIMSVOI ...

  5. 1 Ubuntu 破解帐户密码

    1.  重启Ubuntu  长按shift进入grub界面 2.  选择recovery mode模式,进入Recovery Menu界面选择 root        Drop to root she ...

  6. html5表单上传控件Files筛选指定格式的文件:accept属性过滤excel文件

    摘自:http://blog.csdn.net/jyy_12/article/details/9851349 (IE9及以下不支持下面这些功能,其它浏览器最新版本均已支持.) 1.允许上传文件数量 允 ...

  7. pymysql操作(老版本的,新版有基础不同)

    导入库 import pymysql 创建链接 conn=pymysql.connect(host='127.0.0.1',port='3306',user='root',passwd='123456 ...

  8. Beyond Compare 4解除日期限制,激活版本

    修改注册表 1 在搜索栏中输入 regedit ,打开注册表 2 删除项目:计算机\HKEY_CURRENT_USER\Software\Scooter Software\Beyond Compare ...

  9. AI-图像基础知识-01

        目前人工智能Artificial Intelligence主要分为两大分支: 计算机视常见:Computer Vision,简称CV   CV主要是研究如何让机器看懂世界的一种技术,通过各种光 ...

  10. Nginx 反向代理功能-实现http反向代理

    Nginx 反向代理功能-实现http反向代理 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.