【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

相关文章
|
2天前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
|
2天前
|
设计模式 安全 算法
【Java面试题汇总】设计模式篇(2023版)
谈谈你对设计模式的理解、七大原则、单例模式、工厂模式、代理模式、模板模式、观察者模式、JDK中用到的设计模式、Spring中用到的设计模式
【Java面试题汇总】设计模式篇(2023版)
|
2天前
|
设计模式 算法 安全
设计模式——模板模式
模板方法模式、钩子方法、Spring源码AbstractApplicationContext类用到的模板方法
设计模式——模板模式
|
2天前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑】设计模式——原型模式
对比原型模式和传统方式的实现思路、代码方案、优缺点,阐述原型模式的使用场景,以及深拷贝、浅拷贝等相关概念,并扩展原型模式在Spring源码中的应用。
【Java笔记+踩坑】设计模式——原型模式
|
10天前
|
存储 Java 开发者
【Java新纪元启航】JDK 22:解锁未命名变量与模式,让代码更简洁,思维更自由!
【9月更文挑战第7天】JDK 22带来的未命名变量与模式匹配的结合,是Java编程语言发展历程中的一个重要里程碑。它不仅简化了代码,提高了开发效率,更重要的是,它激发了我们对Java编程的新思考,让我们有机会以更加自由、更加创造性的方式解决问题。随着Java生态系统的不断演进,我们有理由相信,未来的Java将更加灵活、更加强大,为开发者们提供更加广阔的舞台。让我们携手并进,共同迎接Java新纪元的到来!
35 11
|
18天前
|
设计模式 缓存 算法
揭秘策略模式:如何用Java设计模式轻松切换算法?
【8月更文挑战第30天】设计模式是解决软件开发中特定问题的可重用方案。其中,策略模式是一种常用的行为型模式,允许在运行时选择算法行为。它通过定义一系列可互换的算法来封装具体的实现,使算法的变化与客户端分离。例如,在电商系统中,可以通过定义 `DiscountStrategy` 接口和多种折扣策略类(如 `FidelityDiscount`、`BulkDiscount` 和 `NoDiscount`),在运行时动态切换不同的折扣逻辑。这样,`ShoppingCart` 类无需关心具体折扣计算细节,只需设置不同的策略即可实现灵活的价格计算,符合开闭原则并提高代码的可维护性和扩展性。
35 2
|
14天前
|
JSON Java UED
uniapp:使用DCloud的uni-push推送消息通知(在线模式)java实现
以上展示了使用Java结合DCloud的uni-push进行在线消息推送的基本步骤和实现方法。实际部署时,可能需要依据实际项目的规模,业务场景及用户基数进行必要的调整和优化,确保消息推送机制在保证用户体验的同时也满足业务需求。
12 0
|
29天前
|
设计模式
设计模式-单一职责模式
设计模式-单一职责模式
|
29天前
|
设计模式 XML 存储
【二】设计模式~~~创建型模式~~~工厂方法模式(Java)
文章详细介绍了工厂方法模式(Factory Method Pattern),这是一种创建型设计模式,用于将对象的创建过程委托给多个工厂子类中的某一个,以实现对象创建的封装和扩展性。文章通过日志记录器的实例,展示了工厂方法模式的结构、角色、时序图、代码实现、优点、缺点以及适用环境,并探讨了如何通过配置文件和Java反射机制实现工厂的动态创建。
【二】设计模式~~~创建型模式~~~工厂方法模式(Java)
|
29天前
|
设计模式 XML Java
【一】设计模式~~~创建型模式~~~简单工厂模式(Java)
文章详细介绍了简单工厂模式(Simple Factory Pattern),这是一种创建型设计模式,用于根据输入参数的不同返回不同类的实例,而客户端不需要知道具体类名。文章通过图表类的实例,展示了简单工厂模式的结构、时序图、代码实现、优缺点以及适用环境,并提供了Java代码示例和扩展应用,如通过配置文件读取参数来实现对象的创建。
【一】设计模式~~~创建型模式~~~简单工厂模式(Java)