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

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

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. sklearn聚类评价指标

    sklearn中的指标都在sklearn.metric包下,与聚类相关的指标都在sklearn.metric.cluster包下,聚类相关的指标分为两类:有监督指标和无监督指标,这两类指标分别在skl ...

  2. django2.2(一)

    限制请求method 什么是method 1.通常客户端请求服务器获取资源为GET方式 2.客户端提交数据给服务器端数据为POST方式 method限制请求 如果要限制请求,比如客户端只允许用GET方 ...

  3. MySQL事务优化

    ====================事务特性 事务隔离级别 事务控制语句 MySQL优化==================== 事务的概念 事务指逻辑上的一组操作,组成这组操作的各个单元,要么全 ...

  4. sublimeText3和phpstrom使用

    一.sublimtext3 下载地址:http://www.sublimetext.com/3 1.1      安装package control 插件,用来获取和管理插件(sublime包管理工具 ...

  5. shell 的 正则表达式

    shell的正则表达式规则 https://www.jb51.net/tools/shell_regex.html 常规字符 字符 描述 \ 将下一个字符标记为一个特殊字符.或一个原义字符.例如,“n ...

  6. C语言实现归并排序

    #include<stdio.h> #define MAXN 100 //A[p,q] A[q+1,r]是两个有序数组,想办法把他们结合成一个有序数组 void merge(int A[] ...

  7. 性能测试基础---ant集成2

    ·自定义报告模板:因为默认的ant提供的报告模板,是没有tps和90%line这样的数据.但是在实际工作中,这两个统计数据又是必须的,那么我们可以通过自定义(修改)的方式来进行修改,达到我们的目的. ...

  8. 1 NLP学习大纲

    一.自然语言处理概述 1)自然语言处理:利用计算机为工具,对书面实行或者口头形式进行各种各样的处理和加工的技术,是研究人与人交际中以及人与计算机交际中的演员问题的一门学科,是人工智能的主要内容. 2) ...

  9. 关于pytest的命令行传参

    #conftest.py import pytest def pytest_addoption(parser): #parser:用户命令行参数与ini文件值的解析器 # group = parser ...

  10. 201871010109-胡欢欢《面向对象程序设计(java)》第四周学习总结会

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...