当前位置: 首页 > news >正文

JAVA 设计模式 模板方法模式

定义


模板方法模式 (Template Method)
定义了一个操作中的 算法的骨架,而将 部分步骤的实现在子类中完成。
模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

模板方法模式是所有模式中最为常见的几个模式之一,是基于继承代码复用的基本技术。,没有关联关系。 

因此,在模板方法模式的类结构图中,只有继承关系

模板方法模式需要开发抽象类和具体子类的设计师之间的协作。一个设计师负责给出一个算法的轮廓和骨架,另一些设计师则负责给出这个算法的各个逻辑步骤。

代表这些具体逻辑步骤的方法称做 基本方法(primitive method);而将这些基本方法汇总起来的方法叫做 模板方法(template method),这个设计模式的名字就是从此而来。

 


结构


图-模板方法模式结构图

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

复制代码
abstract  class AbstractClass {
     public  abstract  void PrimitiveOperation1();
     public  abstract  void PrimitiveOperation2();
    
     public  void TemplateMethod() {
        PrimitiveOperation1();
        PrimitiveOperation2();
    }
}
复制代码
ConcreteClass : 实现实现父类所定义的一个或多个抽象方法。
复制代码
class ConcreteClassA  extends AbstractClass {
    @Override
     public  void PrimitiveOperation1() {
        System.out.println("具体A类方法1");
    }

    @Override
     public  void PrimitiveOperation2() {
        System.out.println("具体A类方法2");
    }
}

class ConcreteClassB  extends AbstractClass {
    @Override
     public  void PrimitiveOperation1() {
        System.out.println("具体B类方法1");
    }

    @Override
     public  void PrimitiveOperation2() {
        System.out.println("具体B类方法2");
    }    
}
复制代码
测试代码
复制代码
public  class TemplateMethodPattern {
     public  static  void main(String[] args) {
        AbstractClass objA =  new ConcreteClassA();
        AbstractClass objB =  new ConcreteClassB();    
        objA.TemplateMethod();
        objB.TemplateMethod();
    }
}
复制代码



要点


模板方法模式中的三类角色
1、具体方法(Concrete Method)

2、抽象方法(Abstract Method)

3、钩子方法(Hook Method) 

三类角色的关联

在模板方法模式中,首先父类会定义一个算法的框架,即实现算法所必须的所有方法。

其中,具有共性的代码放在父类的具体方法中。

各个子类特殊性的代码放在子类的具体方法中。但是父类中需要有对应抽象方法声明。

钩子方法可以让子类决定是否对算法的不同点进行挂钩。 

总结

使用模板方法模式可以将代码的公共行为提取,以达到复用的目的。

而对于特殊化的行为在子类中实现。父类的模板方法可以控制子类中的具体实现。

子类无需了解整体算法框架,只需实现自己的业务逻辑即可。 

 

 

实例


模板方法模式应用场景十分广泛。

《Head First》的模板方法模式章节里列举了一个十分具有代表性的例子。 

现实生活中,茶和咖啡是随处可见的饮料。冲泡一杯茶或冲泡一杯咖啡的过程是怎样的?

我们来整理一下流程。

泡茶:
烧开水 ==> 冲泡茶叶 ==> 倒入杯中 ==> 添加柠檬
泡咖啡:
烧开水 ==> 冲泡咖啡 ==> 倒入杯中 ==> 添加糖和牛奶

由以上处理步骤不难发现,准备这两种饮料的处理过程非常相似。我们可以使用模板类方法去限定制作饮料的算法框架。

其中相同的具有共性的步骤(如烧开水、倒入杯中),直接在抽象类中给出具体实现。

而对于有差异性的步骤,则在各自的具体类中给出实现。

抽象类
复制代码
abstract  class Beverage {

     //  模板方法,决定了算法骨架。相当于TemplateMethod()方法
     public  void prepareBeverage() {
        boilWater();
        brew();
        pourInCup();
         if (customWantsCondiments())
        {
            addCondiments();
        }
    }
    
     //  共性操作,直接在抽象类中定义
     public  void boilWater() {
        System.out.println("烧开水");
    }
    
     //  共性操作,直接在抽象类中定义
     public  void pourInCup() {
        System.out.println("倒入杯中");
    }
    
     //  钩子方法,决定某些算法步骤是否挂钩在算法中
     public  boolean customWantsCondiments() {
         return  true;
    }
    
     //  特殊操作,在子类中具体实现
     public  abstract  void brew();
    
     //  特殊操作,在子类中具体实现
     public  abstract  void addCondiments();
    
}
复制代码
具体类
复制代码
class Tea  extends Beverage {

    @Override
     public  void brew() {
        System.out.println("冲泡茶叶");
    }

    @Override
     public  void addCondiments() {
        System.out.println("添加柠檬");
    }
    
}

class Coffee  extends Beverage {

    @Override
     public  void brew() {
        System.out.println("冲泡咖啡豆");
    }

    @Override
     public  void addCondiments() {
        System.out.println("添加糖和牛奶");
    }
    
}
复制代码
测试代码
复制代码
public  static  void main(String[] args) {
        
    System.out.println("============= 准备茶 =============");
    Beverage tea =  new Tea();
    tea.prepareBeverage();
    
    System.out.println("============= 准备咖啡 =============");
    Beverage coffee =  new Coffee();
    coffee.prepareBeverage();
    
}
复制代码
运行结果
复制代码
============= 准备茶 =============
烧开水
冲泡茶叶
倒入杯中
添加柠檬
============= 准备咖啡 =============
烧开水
冲泡咖啡豆
倒入杯中
添加糖和牛奶
复制代码



本文转自静默虚空博客园博客,原文链接:http://www.cnblogs.com/jingmoxukong/p/4203714.html,如需转载请自行联系原作者

相关文章:

  • C++primer 9.49
  • springmvc学习笔记--json--返回json的日期格式问题
  • 在php中,如何将一个页面中的标签,替换为用户想输出的内容
  • docker常用命令
  • Java 反射 ParameterizedType 参数化类型
  • 基于jQuery的下拉菜单插件,诸位上眼!!!
  • 【转】整理了一些常用的面试题,掌握了这些基本上就没什么问题了
  • linux 内核库函数 【转】
  • java 切割日期时间段,分割时间段
  • shell、python脚本终端颜色输出
  • 转换图片大小
  • Node.js 新计划:使用 V8 snapshot 将启动速度提升 8 倍
  • Linux系统查看系统是32位还是64位方法总结【转】
  • 扩展Label控件(1) - 实现回发(Postback)功能
  • 使用 Github Pages 发布你的项目文档
  • 「面试题」如何实现一个圣杯布局?
  • 【Leetcode】104. 二叉树的最大深度
  • 【翻译】babel对TC39装饰器草案的实现
  • Apache Pulsar 2.1 重磅发布
  • axios请求、和返回数据拦截,统一请求报错提示_012
  • GDB 调试 Mysql 实战(三)优先队列排序算法中的行记录长度统计是怎么来的(上)...
  • iOS高仿微信项目、阴影圆角渐变色效果、卡片动画、波浪动画、路由框架等源码...
  • Javascripit类型转换比较那点事儿,双等号(==)
  • js继承的实现方法
  • python学习笔记 - ThreadLocal
  • 二维平面内的碰撞检测【一】
  • 关于springcloud Gateway中的限流
  • 什么软件可以剪辑音乐?
  • 微信开源mars源码分析1—上层samples分析
  • 移动端 h5开发相关内容总结(三)
  • 优秀架构师必须掌握的架构思维
  • 由插件封装引出的一丢丢思考
  • 蚂蚁金服CTO程立:真正的技术革命才刚刚开始
  • 昨天1024程序员节,我故意写了个死循环~
  • #{}和${}的区别?
  • (39)STM32——FLASH闪存
  • (附源码)spring boot智能服药提醒app 毕业设计 102151
  • (一)基于IDEA的JAVA基础12
  • (转)项目管理杂谈-我所期望的新人
  • .bat批处理(二):%0 %1——给批处理脚本传递参数
  • .bat批处理(十一):替换字符串中包含百分号%的子串
  • .Net - 类的介绍
  • .net Application的目录
  • .net framwork4.6操作MySQL报错Character set ‘utf8mb3‘ is not supported 解决方法
  • .NET/C# 项目如何优雅地设置条件编译符号?
  • .net和jar包windows服务部署
  • .pyc文件是什么?
  • @RequestParam,@RequestBody和@PathVariable 区别
  • [ 渗透工具篇 ] 一篇文章让你掌握神奇的shuize -- 信息收集自动化工具
  • []FET-430SIM508 研究日志 11.3.31
  • [17]JAVAEE-HTTP协议
  • [2021]Zookeeper getAcl命令未授权访问漏洞概述与解决
  • [BZOJ1010] [HNOI2008] 玩具装箱toy (斜率优化)
  • [codeforces]Levko and Permutation
  • [codevs] 1029 遍历问题