java设计模式之模板方法模式详解

一、什么是模板方法模式

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

  通俗的讲,模板方法模式是通过把不变行为搬到超类,去除子类里面的重复代码提现它的优势,它提供了一个很好的代码复用平台。当不可变和可变的方法在子类中混合在一起的时候,不变的方法就会在子类中多次出现,这样如果摸个方法需要修改则需要修改很多个,虽然这个这个问题在设计之初就应该想好。这个时候模板方法模式就起到了作用了,通过模板方法模式把这些重复出现的方法搬到单一的地方,这样就可以帮助子类摆脱重复不变的纠缠。

  举个好懂的例子,小时候笔者家里穷,在农村上小学的时候考试都是每个学生手抄试卷,因为那个时候学校还没有试卷印刷。全班五十多个学生每个学生都要重复抄一遍黑板的试卷,并且像笔者这样的近视眼很容易就抄错了,8抄成3,7抄成1等到,然后明明做对了但是分数就是不高,导致笔者一直是全班倒数。这就是个很严重的重复不可变的问题,现在条件好了不少,学生不需要抄试卷,试卷印刷就解决了这个重复抄试卷的问题。模板方法也是类似。

二、模式对比

1、抄试卷模式

笔者就以抄试卷模式为名来阐述重复不变带来的不便,下面会对该模式进行改进。

学生甲抄的试卷

public class TestPaperA {
 //试卷第一题
 public void testQuestion1(){
  System.out.println("小龙女是杨过的什么亲戚?() A.小姨妈 B.大姨妈 C.姑妈 D.舅妈");
  System.out.println("答案:C");
 }

 //试卷第二题
 public void testQuestion2(){
  System.out.println("全真教的首任掌门是谁?A.周伯通 B.欧阳锋 C.王重阳 D.西门吹牛");
  System.out.println("答案:C");
 }

 //试卷第三题
 public void testQuestion3(){
  System.out.println("《天龙八部》中被封为南院大王的大侠是谁?A.段誉 B.乔峰 C.慕容复 D.段智兴");
  System.out.println("答案:B");
 }
}

学生乙抄的试卷

public class TestPaperB {
 //试卷第一题
 public void testQuestion1(){
  System.out.println("小龙女是杨过的什么亲戚?() A.小姨妈 B.大姨妈 C.姑妈 D.舅妈");
  System.out.println("答案:A");
 }

 //试卷第二题
 public void testQuestion2(){
  System.out.println("全真教的首任掌门是谁?A.周伯通 B.欧阳锋 C.王重阳 D.西门吹牛");
  System.out.println("答案:C");
 }

 //试卷第三题
 public void testQuestion3(){
  System.out.println("《天龙八部》中被封为南院大王的大侠是谁?A.段誉 B.乔峰 C.慕容复 D.段智兴");
  System.out.println("答案:D");
 }
}

客户端代码

public class ShowAnswer {

 public static void main(String[] args) {
  System.out.println("学生甲的试卷");
  TestPaperA stuA = new TestPaperA();
  stuA.testQuestion1();
  stuA.testQuestion2();
  stuA.testQuestion3();
  System.out.println("学生乙的试卷");
  TestPaperB stuB = new TestPaperB();
  stuB.testQuestion1();
  stuB.testQuestion2();
  stuB.testQuestion3();
 }

}

很容易发现上面两个学生抄的试卷有很多重复的地方,比如试卷的题目,输出答案的方法,这些都在每个学生试卷类中混合在一起了,既不利于维护,也不利于浏览,下面看一下模板方法模式是怎么改进的。

2、模板方法模式

将每个学生试卷的重复部分提取出来,题目,作答等等。

首先改造试卷类,将该类改为抽象类,在该类中我添加了三个抽象的方法用于子类实现,学生都是要作答的,但是答案不一样,所以可以将作答的过程作为重复不变的方法提取出来,代码如下。

public abstract class TestPaper {
 //试卷第一题
 public void testQuestion1(){
  System.out.println("小龙女是杨过的什么亲戚?() A.小姨妈 B.大姨妈 C.姑妈 D.舅妈");
  System.out.println("答案:" + answer1());
 }

 //试卷第二题
 public void testQuestion2(){
  System.out.println("全真教的首任掌门是谁?A.周伯通 B.欧阳锋 C.王重阳 D.西门吹牛");
  System.out.println("答案:" + answer2());
 }

 //试卷第三题
 public void testQuestion3(){
  System.out.println("《天龙八部》中被封为南院大王的大侠是谁?A.段誉 B.乔峰 C.慕容复 D.段智兴");
  System.out.println("答案:" + answer3());
 }

 //这三个钩子方法是给每个子类去实现,并返回答案的
 public abstract String answer1();
 public abstract String answer2();
 public abstract String answer3();

 //模板方法,考试的过程,定义基本的考试过程,子类回调
 public void exam(){
  testQuestion1();
  testQuestion2();
  testQuestion3();
 }
}

首先来看第一个学生的考试情况

public class TestPaperA extends TestPaper{

 @Override
 public String answer1() {
  return "A";
 }

 @Override
 public String answer2() {
  return "B";
 }

 @Override
 public String answer3() {
  return "D";
 }

}

其他学生的试卷可能答案不是一样的,但是基本的答题过程就是一样的,所以就不重复写了,下面看下客户端代码。

public class ShowAnswer {

 public static void main(String[] args) {
  TestPaper testPaper = new TestPaperA();
  testPaper.exam();
 }

}

可以看待客户端代码也减轻了很多,这样逻辑清晰,利于维护,优势很明显,下面看下具体答题情况。

小龙女是杨过的什么亲戚?() A.小姨妈  B.大姨妈  C.姑妈  D.舅妈
答案:A
全真教的首任掌门是谁?A.周伯通 B.欧阳锋 C.王重阳 D.西门吹牛
答案:B
《天龙八部》中被封为南院大王的大侠是谁?A.段誉 B.乔峰 C.慕容复 D.段智兴
答案:D

3、模板方法模式的基本结构

AbstractClass是一个抽象类,其实就是一个抽象模板,定义并实现了一个模板方法。这个模板方法一般是一个具体的实现,他给出了一些逻辑的骨架,而逻辑的组成在相应的抽象类中,推迟到了子类实现。代码如下

public abstract class AbstractClass {

 //一些抽象行为,可以理解为重复不变的方法,提取到抽象类
 public abstract void primitiveOperation1();
 public abstract void primitiveOperation2();

 //模板方法,给出了具体逻辑的骨架,而逻辑的组成是一些相应的抽象操作,他们都推迟到子类实现
 public void templateMothed(){
  primitiveOperation1();
  primitiveOperation2();
 }

}

ConcreteClass,实现父类所定义的一个或多个抽象方法。每一个AbstractClass都可以有一个或者多个ConcreteClass与之对应,而每一个ConcreteClass都可以给出这些抽象方法(也就是骨架的组成步骤)的不同实现,从而得到的实现都不同。

public class ConcreteClassA extends AbstractClass{

 @Override
 public void primitiveOperation1() {
  System.out.println("子类A的操作1");
 }

 @Override
 public void primitiveOperation2() {
  System.out.println("子类A的操作2");
 }

}
public class ConcreteClassB extends AbstractClass{

 @Override
 public void primitiveOperation1() {
  System.out.println("子类B的操作1");
 }

 @Override
 public void primitiveOperation2() {
  System.out.println("子类B的操作2");
 }

}

上面定义了两个具体的实现,更多的实现其实都是一致的,这里就不多多说了。下面看下客户端代码

public class Show {

 public static void main(String[] args) {
  AbstractClass c;
  c = new ConcreteClassA();
  c.templateMothed();
  c = new ConcreteClassB();
  c.templateMothed();
 }

}

输入如下

子类A的操作1
子类A的操作2
子类B的操作1
子类B的操作2

4、UML图

三、总结

  模板方法模式就是为了将重复不变的代码提取到一个抽象类中。当我们要完成在某一细节层次一致的一个过程或一系列步骤,但其个别步骤在更详细的层次上的实现可能不同时,我们通常考虑用模板方法模式来处理。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 深入解析Java的设计模式编程中的模板方法模式

    定义:  定义一个操作中的算法的框架,而将一些步骤延迟到子类中.使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤. 听起来好高端的样子,我的理解: 1.父类声明了若干个抽象方法(基本方法)和若干个具体方法(模板方法) 2.抽象方法是一个算法(过程)的步骤,在子类中实现 3.模板方法是一个算法(过程)的框架,在父类中已经约定好,实现对基本方法调用,完成固定的逻辑 4.一个算法(过程)的结构在父类中定义,具体的实现细节则在子类中实现 注:为了防止恶意操作,一般模板方法都加上final

  • Java设计模式之模板模式(Template模式)介绍

    Template模式定义:定义一个操作中算法的骨架,将一些步骤的执行延迟到其子类中. 其实Java的抽象类本来就是Template模式,因此使用很普遍.而且很容易理解和使用,我们直接以示例开始: 复制代码 代码如下: public abstract class Benchmark { /** * 下面操作是我们希望在子类中完成 */ public abstract void benchmark(); /** * 重复执行benchmark次数 */ public final long repea

  • Java经典设计模式之策略模式原理与用法详解

    本文实例讲述了Java经典设计模式之策略模式.分享给大家供大家参考,具体如下: 策略模式指:策略模式指将程序中可变部分抽象分离成一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式让算法独立于使用它的客户而独立变化. 策略模式一般由下面三部分组成: 1. 抽象策略角色: 策略类,通常由一个接口或者抽象类实现. 2. 具体策略角色:包装了相关的算法和行为. 3. 环境角色:持有某一个策略类的引用,客户端调用. 策略模式设计原则: 1. 把程序中需要变化的部分抽离出来,独立于不变

  • 举例讲解Java设计模式编程中模板方法模式的运用实例

    模板方法模式定义为: 在一个方法中定义了一个算法的骨架或者步骤,而将一些步骤延迟到子类中去实现.模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某一些步骤. 模板方法在基类中定义了一个操作的流程顺序,能够保证该步骤按序进行,有一些步骤的具体实现在基类中已经声明,而将一些变化的步骤的具体实现交给了子类去实现,从而就达到了延迟一些步骤到子类中,模板方法一个最大的好处就是能够设定一个业务流程能够按照一定严格的顺序执行,控制了整个算法的执行步骤. 这个方法将算法定义成一组步骤,其中凡是想让

  • Java设计模式之装饰者模式详解和代码实例

    装饰者模式可以给已经存在的对象动态的添加能力.下面,我将会用一个简单的例子来演示一下如何在程序当中使用装饰者模式. 1.装饰者模式 让我们来假设一下,你正在寻找一个女朋友.有很多来自不同国家的女孩,比如:美国,中国,日本,法国等等,他们每个人都有不一样的个性和兴趣爱好,如果需要在程序当中模拟这么一种情况的话,假设每一个女孩就是一个Java类的话,那么就会有成千上万的类,这样子就会造成类的膨胀,而且这样的设计的可扩展性会比较差.因为如果我们需要一个新的女孩,就需要创建一个新的Java类,这实际上也

  • Java设计模式之观察者模式_动力节点Java学院整理

    定义:定义对象间一种一对多的依赖关系,使得当每一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新. 类型:行为类模式 类图: 在软件系统中经常会有这样的需求:如果一个对象的状态发生改变,某些与它相关的对象也要随之做出相应的变化.比如,我们要设计一个右键菜单的功能,只要在软件的有效区域内点击鼠标右键,就会弹出一个菜单:再比如,我们要设计一个自动部署的功能,就像eclipse开发时,只要修改了文件,eclipse就会自动将修改的文件部署到服务器中.这两个功能有一个相似的地方,那就是一个对象

  • Java经典设计模式之适配器模式原理与用法详解

    本文实例讲述了Java经典设计模式之适配器模式.分享给大家供大家参考,具体如下: 适配器模式是把一个类的接口适配成用户所期待的,使得原本由于接口不兼容而不能一起工作的一些类可以在一起工作从而实现用户所期望的功能. 适配器模式的优势: 1. 通过适配器,客户端可以调用统一接口,操作简单直接,并且代码逻辑紧凑,使用起来方便. 2. 代码复用,适配器模式就是解决因为环境要求不相同 的问题,通过适配实现代码复用. 3. 将目标类和适配器类解耦,通过新建一个适配器类来重用现在的类,不用再去重复修改原有代码

  • Java设计模式之工厂模式(Factory模式)介绍

    工厂模式定义:提供创建对象的接口. 为何使用工厂模式 工厂模式是我们最常用的模式了,著名的Jive论坛,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见. 为什么工厂模式是如此常用?因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑实用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量. 我们以类Sample为例,

  • Java经典设计模式之模板方法模式定义与用法示例

    本文实例讲述了Java设计模式之模板方法模式.分享给大家供大家参考,具体如下: 我们在生活中,很多事情都包含特定的一些步骤.如去银行办理业务,通常步骤的次序是:取号 –> 填单 –> 等待叫号–>办理业务.这几个步骤中,有的是不变的,比如取号,每个人都要取,但有的是要变的,比如都有填单,但是根据不同的业务,填写的单据不同.又比如我们外出吃饭,一般的步骤是:点餐–>等待–>吃饭–>付钱,也能发现同样的规律.这样的事情数不胜数. 项目开发中,也可能遇到这样的情况,多个功能模

  • Java经典设计模式之责任链模式原理与用法详解

    本文实例讲述了Java经典设计模式之责任链模式.分享给大家供大家参考,具体如下: 责任链模式:多个对象由其对象对应下家的引用连成一条链,请求在这个链上传递,直到链上的某一个接收对象处理此请求.因为请求的客户端并不知道链上最终是谁来处理这个请求,使得系统可以在不影响客户端的情况下动态地重新组织和分配责任,从而避免了请求发送者与请求处理者之间的耦合. 责任链械中涉及到三种角色: 1,抽象处理者角色 2,具体处理者角色 3,请求发送者 小例子:假设去买房子,买房子就需要砍价, 卖房的人职位不同,可以优

  • Java设计模式之命令模式_动力节点Java学院整理

    定义:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能. 类型:行为类模式 类图: 命令模式的结构 顾名思义,命令模式就是对命令的封装,首先来看一下命令模式类图中的基本结构: Command类:是一个抽象类,类中对需要执行的命令进行声明,一般来说要对外公布一个execute方法用来执行命令. ConcreteCommand类:Command类的实现类,对抽象类中声明的方法进行实现. Client类:最终的客户端调用类.

随机推荐