【java设计模式】之 模板方法(Template Method)模式-阿里云开发者社区

开发者社区> ghost丶桃子> 正文

【java设计模式】之 模板方法(Template Method)模式

简介:
+关注继续查看

目录(?)[+]

1. 模板方法的一个实例

        这一节主要来学习一下设计模式中的模板方法模式。我们先来看一个例子:假如现在老板让你做一个汽车的模型,要求只要完成基本功能即可,不考虑扩展性,那你会怎么做呢?我们首先会根据经验设计一个类图:

       由这个类图可知,非常简单的实现了悍马车,该车有两个型号H1和H2。那现在我们开始实现这两个型号的悍马车,首先我们得把抽象类写好,然后两个不同的模型实现类通过简单的继承就可以实现要求。首先看看抽象类的代码:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public abstract class HummerModel {  
  2.     public abstract void start(); //发动  
  3.     public abstract void stop();  //停止  
  4.     public abstract void alarm(); //鸣笛  
  5.     public abstract void engineBoom(); //轰鸣  
  6.     public abstract void run(); //车总归要跑  
  7. }  
        简单到不行,下面我们来实现两个悍马的模型:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. //悍马H1  
  2. public class HummerH1 implements HummerModel {  
  3.   
  4.     @Override  
  5.     public void start() {  
  6.         System.out.println("H1发动……");  
  7.     }  
  8.   
  9.     @Override  
  10.     public void stop() {  
  11.         System.out.println("H1停止……");  
  12.     }  
  13.   
  14.     @Override  
  15.     public void alarm() {  
  16.         System.out.println("H1鸣笛……");  
  17.     }  
  18.   
  19.     @Override  
  20.     public void engineBoom() {  
  21.         System.out.println("H1轰鸣……");  
  22.     }  
  23.   
  24.     @Override  
  25.     public void run() {  
  26.         this.start();  
  27.         this.engineBoom();  
  28.         this.alarm();  
  29.         this.stop();  
  30.     }  
  31. }  
  32.   
  33. //悍马H2  
  34. public class HummerH2 implements HummerModel {  
  35.   
  36.     @Override  
  37.     public void start() {  
  38.         System.out.println("H2发动……");  
  39.     }  
  40.   
  41.     @Override  
  42.     public void stop() {  
  43.         System.out.println("H2停止……");  
  44.     }  
  45.   
  46.     @Override  
  47.     public void alarm() {  
  48.         System.out.println("H2鸣笛……");  
  49.     }  
  50.   
  51.     @Override  
  52.     public void engineBoom() {  
  53.         System.out.println("H2轰鸣……");  
  54.     }  
  55.   
  56.     @Override  
  57.     public void run() {  
  58.         this.start();  
  59.         this.engineBoom();  
  60.         this.alarm();  
  61.         this.stop();  
  62.     }  
  63. }  
        很明显,已经发现代码有点问题了,两个悍马的run方法完全相同。所以这个run方法应该出现在抽象类中,不应该在实现类中,抽象是所有子类的共性封装。所以我们修改一下抽象类:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public abstract class HummerModel {  
  2.     public abstract void start(); //发动  
  3.     public abstract void stop();  //停止  
  4.     public abstract void alarm(); //鸣笛  
  5.     public abstract void engineBoom(); //轰鸣  
  6.     public void run() { //车总归要跑  
  7.         this.start();  
  8.         this.engineBoom();  
  9.         this.alarm();  
  10.         this.stop();  
  11.     }  
  12. }  
        这样两个实现类就不用实现run方法了,可以直接拿来用。其实,这就是模板方法模式。

2. 模板方法模式的定义

        模板方法模式很简单,它的定义是:Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses define certain steps of an algorithm without changing the algorithm's structure. 即定义一个操作中的算法框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可冲定义该算法的某些特定步骤。模板方法模式的通用类图如下:

        模板方法模式确实很简单,仅仅使用了Java的继承机制,但是它是一个应用非常广泛的模式,其中AbstractClass叫做抽象模板,它的方法分为两类:基本方法(由子类去实现)和模板方法(可以有一个或多个,也就是一个框架,实现对基本方法的调度,完成固定的逻辑)。为了防止恶意的操作,一般模板方法上都添加上final关键字,不允许被覆写。我们来看一下AbstractClass模板:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public abstract class AbstractClass {  
  2.     //基本方法  
  3.     protected abstract void doSomething();  
  4.     protected abstract void doAnything();  
  5.     //模板方法  
  6.     public void templateMethod() {  
  7.         //调用基本方法,完成相关的逻辑  
  8.         this.doAnything();  
  9.         this.doSomething();  
  10.     }  
  11. }  
        具体实现类就不写了……

3. 模板方法模式的优缺点

      优点:

        1)封装不变部分,扩展可变部分:把认为不变部分的算法封装到父类实现,可变部分则可以通过继承来实现,很容易扩展。

        2)提取公共部分代码,便于维护:上面悍马的例子就是个很好的解释。

        3)行为由父类控制,由子类实现。

      缺点:

        模板方法模式颠倒了我们平常的设计习惯:抽象类负责声明最抽象、最一般的事物属性和方法,实现类实现具体的事物属性和方法。在复杂的项目中可能会带来代码阅读的难度。

4. 模板方法模式的扩展

        还是上面那个悍马的例子,现在老板说这车干嘛跑起来就要鸣笛,太吵了,难道不是应该让用户决定它是否要鸣笛么?好像确实是这样的……那好办,我们可以修改一下抽象模板类中的方法:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public abstract class HummerModel {  
  2.     protected abstract void start(); //发动  
  3.     protected abstract void stop();  //停止  
  4.     protected abstract void alarm(); //鸣笛  
  5.     protected abstract void engineBoom(); //轰鸣  
  6.     final public void run() { //车总归要跑  
  7.         this.start();  
  8.         this.engineBoom();  
  9.         if(this.isAlarm()) {//想让它叫就叫,不想就不叫        
  10.             this.alarm();  
  11.         }  
  12.         this.stop();  
  13.     }  
  14.     protected boolean isAlarm() { //我们加了一个判断方法,默认返回true  
  15.         return true;  
  16.     }  
  17. }  
       我们在模板类中增加了一个判断方法来判断是否要鸣笛,现在就好办了,具体实现类只要重写这个方法就可以做到人为控制是否要鸣笛了,下面我们来看一下实现类:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public class HummerH1 extends HummerModel {  
  2.   
  3.     private boolean alarmFlag = true//判断标记  
  4.     @Override  
  5.     public void start() {  
  6.         System.out.println("H1发动……");  
  7.     }  
  8.   
  9.     @Override  
  10.     public void stop() {  
  11.         System.out.println("H1停止……");  
  12.     }  
  13.   
  14.     @Override  
  15.     public void alarm() {  
  16.         System.out.println("H1鸣笛……");  
  17.     }  
  18.   
  19.     @Override  
  20.     public void engineBoom() {  
  21.         System.out.println("H1轰鸣……");  
  22.     }  
  23.       
  24.     @Override  
  25.     protected boolean isAlarm() { //覆写isAlarm方法,返回判断标记  
  26.         return this.alarmFlag;  
  27.     }  
  28.       
  29.     public void setAlarm(boolean isAlarm) { //设置判断标记  
  30.         this.alarmFlag = isAlarm;  
  31.     }  
  32.       
  33. }  
        这个实现很好,我们在实现类中定义一个判断标记,然后对外提供一个public接口setAlarm来让外界设置这个判断标记,这就像是开关一样,想让它ture和false都行。这个isAlarm方法俗称钩子方法。有了钩子方法的模板方法模式才算完美,大家可以想象一下,由子类的一个方法返回值决定公共部分的执行结果,这个是很有吸引力的。我们来测试一下:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public class Test {  
  2.     public static void main(String[] args) throws IOException {  
  3.         System.out.println("----H1型悍马----");  
  4.         System.out.println("是否需要喇叭声响? 0-不需要  1-需要");  
  5.         String type = new BufferedReader(new InputStreamReader(System.in)).readLine();  
  6.         HummerH1 h1 = new HummerH1();  
  7.         if(type.equals("0")) {  
  8.             h1.setAlarm(false);  
  9.         }  
  10.         h1.run();  
  11.     }  
  12. }  

        当输入不同的指令后,就会决定不同的动作:即要不要鸣笛,至此,这个模板方法模式就介绍完了。

        相关阅读:http://blog.csdn.net/column/details/des-pattern.html

_____________________________________________________________________________________________________________________________________________________

-----乐于分享,共同进步!

-----更多文章请看:http://blog.csdn.net/eson_15

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
java多线程:并发包中ReentrantReadWriteLock读写锁的锁降级模板
写锁降级为读锁,但读锁不可升级或降级为写锁。 锁降级是为了让当前线程感知到数据的变化。 1 //读写锁 2 private ReentrantReadWriteLock lock=new ReentrantReadWriteLock(); 3 //读锁 4 private ReadLock readLock=lock.
714 0
JAVA之旅(七)——final关键字 , 抽象类abstract,模板方法模式,接口interface,implements,特点,扩展
JAVA之旅(七)——final关键字 , 抽象类abstract,模板方法模式,接口interface,implements,特点,扩展 一.final 我们来聊聊final这个关键字 final可以修饰类,方法和变量 final修饰的类不可以被继承 final修饰的方法不可以被覆盖 fi.
1068 0
FreeMarker之根据模板生成Java代码
FreeMarker根据模板生成Java代码,光这句话,大家想必也知道它的应用了,比如流行的DRY原则,该原则的意思,可简单概述为"不要写重复的代码"。 比如Java中三层架构,数据访问层,业务逻辑层,表现层,光这三层就出现重复性的增删改查及其相关的界面代码。
2062 0
用阿里云建网站三种方式(自助建站+模板建站+功能定制建站)
站长分享利用阿里云创建网站的三种方式及优势对比
111 0
用阿里云建网站三种方式(自助建站+模板建站+功能定制建站)
站长分享利用阿里云创建网站的三种方式及优势对比
185 0
1955
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载