JAVA 设计模式 模板方法模式
定义
模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
模板方法模式是所有模式中最为常见的几个模式之一,是基于继承的代码复用的基本技术。,没有关联关系。
因此,在模板方法模式的类结构图中,只有继承关系。
模板方法模式需要开发抽象类和具体子类的设计师之间的协作。一个设计师负责给出一个算法的轮廓和骨架,另一些设计师则负责给出这个算法的各个逻辑步骤。
结构

AbstractClass : 抽象类,定义并实现一个模板方法。这个模板方法定义了算法的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类去实现。顶级逻辑也有可能调用一些具体方法。
public abstract void PrimitiveOperation1();
public abstract void PrimitiveOperation2();
public void TemplateMethod() {
PrimitiveOperation1();
PrimitiveOperation2();
}
}
@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 static void main(String[] args) {
AbstractClass objA = new ConcreteClassA();
AbstractClass objB = new ConcreteClassB();
objA.TemplateMethod();
objB.TemplateMethod();
}
}
要点
2、抽象方法(Abstract Method)
3、钩子方法(Hook Method)
三类角色的关联
在模板方法模式中,首先父类会定义一个算法的框架,即实现算法所必须的所有方法。
其中,具有共性的代码放在父类的具体方法中。
各个子类特殊性的代码放在子类的具体方法中。但是父类中需要有对应抽象方法声明。
钩子方法可以让子类决定是否对算法的不同点进行挂钩。
总结
使用模板方法模式可以将代码的公共行为提取,以达到复用的目的。
而对于特殊化的行为在子类中实现。父类的模板方法可以控制子类中的具体实现。
子类无需了解整体算法框架,只需实现自己的业务逻辑即可。
实例
模板方法模式应用场景十分广泛。
现实生活中,茶和咖啡是随处可见的饮料。冲泡一杯茶或冲泡一杯咖啡的过程是怎样的?
我们来整理一下流程。
泡茶: 烧开水 ==> 冲泡茶叶 ==> 倒入杯中 ==> 添加柠檬 泡咖啡: 烧开水 ==> 冲泡咖啡 ==> 倒入杯中 ==> 添加糖和牛奶 |
由以上处理步骤不难发现,准备这两种饮料的处理过程非常相似。我们可以使用模板类方法去限定制作饮料的算法框架。
其中相同的具有共性的步骤(如烧开水、倒入杯中),直接在抽象类中给出具体实现。
而对于有差异性的步骤,则在各自的具体类中给出实现。
// 模板方法,决定了算法骨架。相当于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();
}
@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("添加糖和牛奶");
}
}
System.out.println("============= 准备茶 =============");
Beverage tea = new Tea();
tea.prepareBeverage();
System.out.println("============= 准备咖啡 =============");
Beverage coffee = new Coffee();
coffee.prepareBeverage();
}
烧开水
冲泡茶叶
倒入杯中
添加柠檬
============= 准备咖啡 =============
烧开水
冲泡咖啡豆
倒入杯中
添加糖和牛奶
本文属于 JAVA设计模式系列 。
《大话设计模式》
《HeadFirst设计模式》相关文章:
这类程序员成华为宠儿,分分钟秒杀众应届毕业生
近日,华为20亿奖励员工的新闻频频刷屏。其中20亿奖金不是面向所有的华为员工,20亿奖金包涉及到的是研发体系、造AI芯片和建设生态的员工。从5G开始部署以来,华为获得了来自全球各地运营商的订单,签订了40多个5G商用合同。另外华为…

Swift 使用CoreLocation获取定位与位置信息
大多数情况下APP会在开启应用的时候获取当前的位置,所以我写在APPDelegate里第一步 import CoreLocationvar locationManager CLLocationManager() 第二步func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: …

FFmpeg在Windows上设置dshow mjpeg编码+libyuv解码显示测试代码
之前在https://blog.csdn.net/fengbingchun/article/details/103444891中介绍过在Windows上通过ffmpeg dshow设置为mjpeg编解码方式进行实时显示的测试代码。这里测试仅调用ffmpeg的mjpeg编码接口,获取到packet后,通过libyuvlibjpeg-turbo对mjpeg进行解码…

转:浅谈Linux的内存管理机制
一 物理内存和虚拟内存 我们知道,直接从物理内存读写数据要比从硬盘读写数据要快的多,因此,我们希望所有数据的读取和写入都在内存完成,而内存是有限的,这样就引出了物理内存与虚拟内存的概念。 物理内存就是系统硬件提…

swift3.0阿里百川反馈
闲言少叙 直接上不熟 1.导入自己工程阿里百川demo中的Util文件,并引用其中的头文件 2.剩余就是swift3.0代码.在自己需要的地方书写 (前提是你已经申请了APPKey) 3.代码 //调用意见反馈 func actionOpenFeedback(){ //key self.appKey "此处填写自己申请的key" s…
通俗易懂:8大步骤图解注意力机制
作者 | Raimi Karim译者 | 夕颜出品 | AI科技大本营(ID:rgznai100)【导读】这是一份用图片和代码详解自注意力机制的指南,请收好。BERT、RoBERTa、ALBERT、SpanBERT、DistilBERT、SesameBERT、SemBERT、MobileBERT、TinyBERT和CamemBERT的共同…

Windows上VS2017单步调试FFmpeg源码的方法
之前在https://blog.csdn.net/fengbingchun/article/details/90114411 介绍过如何在Windows7/10上通过MinGW方式编译FFmpeg 4.1.3源码生成库的步骤,那时只能生成最终的库,却不能产生vs工程,无法进行单步调试。GitHub上有个项目ShiftMediaProj…

ormlite 多表联合查询
ormlite 多表联合查询 QueryBuilder shopBrandQueryBuilder shopBrandDao.queryBuilder(); QueryBuilder shopQueryBuilder shopDao.queryBuilder();Where shopBrandWhere shopBrandQueryBuilder.where(); shopBrandWhere .eq(ShopBrand.SHOP_NO, shopNo);Where shopWhere …

C++中关键字volatile和mutable用法
C/C中的volatile关键字和const对应,用来修饰变量,用于告诉编译器该变量值是不稳定的,可能被更改。使用volatile注意事项: (1). 编译器会对带有volatile关键字的变量禁用优化(A volatile specifier is a hint to a compiler that …
基于生成对抗网络(GAN)的人脸变形(附链接) | CSDN博文精选
扫码参与CSDN“原力计划”翻译 | 张一豪校对 | 吴金笛来源 | 数据派THU*点击阅读原文,查看「CSDN原力计划」详细说明。本文详细介绍了生成对抗网络(GAN)的知识,并用其变换人脸,并探寻如何利用StyleGAN生成不同属性&…

Jmeter连接Oracle数据库
一、Jmeter要连接oracle数据库,就必须复制JDBC驱动jar包文件ojdbc14.jar到Jmeter的lib目录下二、进入Jmeter的bin目录运行Jmeter.bat,启动Jmeter三、Jmeter软件配置如下:1、添加线程组右击线程组,选择“添加--配置元件--JDBC Conn…

swift3.0友盟分享
经过(一)的讲解,大家应该可以按照友盟提供的测试账号可以集成友盟分享了,友盟目前集合了18个APP共27种分享,可以授权的有10个App:微信、QQ、新浪微博、腾讯微博、人人网、豆瓣、Facebook、Twitter、Linkedi…

C++11中std::future的使用
C11中的std::future是一个模板类。std::future提供了一种用于访问异步操作结果的机制。std::future所引用的共享状态不能与任何其它异步返回的对象共享(与std::shared_future相反)( std::future references shared state that is not shared with any other asynchronous retur…
给算法工程师和研究员的「霸王餐」| 附招聘信息
现在的算法工程师真的是太难了!要让AI会看人眼都分辨不清的医疗影像!数据又不够,还得用前沿技术!好不容易学会看片,还要让AI会分析病理!然后模型搞出来了,还要把几十种模型,做N次计算…

swift3.0三种反向传值
一 :通知 1.通知传值所用方法 // MARK: - private methods(内部接口) let NotifMycation NSNotification.Name(rawValue:"MyNSNotification") func tempbuttonAction() { //这个方法可以传一个值 NotificationCenter.default.post(name: NotifMycation, object: &q…

C++11中std::shared_future的使用
C11中的std::shared_future是个模板类。与std::future类似,std::shared_future提供了一种访问异步操作结果的机制;不同于std::future,std::shared_future允许多个线程等待同一个共享状态;不同于std::future仅支持移动操作…
聊聊抖音、奈飞、Twitch、大疆、快手、B站的多媒体关键技术
随着5G牌照发放,5G终端正在迎来集中上市潮,对于5G带来的变革一触即发。目前互联网上超过七成的流量来自多媒体,未来这个比例将超过八成。音视频就像空气和水一样普及,深度到每个人的生活和工作中。同时,深度学习技术则…

Linux安全事件应急响应排查方法总结
Linux安全事件应急响应排查方法总结 Linux是服务器操作系统中最常用的操作系统,因为其拥有高性能、高扩展性、高安全性,受到了越来越多的运维人员追捧。但是针对Linux服务器操作系统的安全事件也非常多的。攻击方式主要是弱口令攻击、远程溢出攻击及其他…

C++11中std::packaged_task的使用
C11中的std::packaged_task是个模板类。std::packaged_task包装任何可调用目标(函数、lambda表达式、bind表达式、函数对象)以便它可以被异步调用。它的返回值或抛出的异常被存储于能通过std::future对象访问的共享状态中。 std::packaged_task类似于std::function,…

Swift3.0和OC桥接方法
1.直接在工程中commandn,出现如图,点击Header File创建桥接文件Bridging-Header.h,如图: 2.点击next,出现如图画面,一定要记得勾选第一项,再点击create创建完成。 3.配置桥接文件,点击target - …

量子算命,在线掷筊:一个IBM量子云计算机的应用实践,代码都有了
整理 | Jane 出品| AI科技大本营(ID:rgznai100) “算命”,古今中外,亘古不衰的一门学问,哪怕到了今天,大家对算命占卜都抱着一些”敬畏“的信任心理,西方流行塔罗牌,国…

rails应用ajax之二:使用rails自身支持
考虑另一种情况: 1. 页面上半部分显示当前的所有用户,页面下半部分是输入新用户的界面; 2. 每当输入新用户时,页面上半部分会动态更新新加用户的内容; 我们还是用ajax实现,不过这次用rails内部对ajax的支持…

C++11中std::async的使用
C11中的std::async是个模板函数。std::async异步调用函数,在某个时候以Args作为参数(可变长参数)调用Fn,无需等待Fn执行完成就可返回,返回结果是个std::future对象。Fn返回的值可通过std::future对象的get成员函数获取。一旦完成Fn的执行&…
BAT数据披露:缺人!110万AI人才缺口,两者矛盾,凉凉了!
人工智能到底有多火?近日国内首份《BAT人工智能领域人才发展报告》新鲜出炉,此次报告是针对国内人工智能领域的人才争夺情况进行了梳理。并把研究对象锁定在BAT三大巨头的身上。来源:《BAT人工智能领域人才发展报告》其中得出最为核心的结论&…

swift3.0最新拨打电话方法
let alertVC : UIAlertController UIAlertController.init(title: "是否拨打报警电话:10086", message: "", preferredStyle: .alert) let falseAA : UIAlertAction UIAlertAction.init(title: "取消", style: .cancel, handler: nil) let tr…

关于手机已处理里重复单据的处理办法
更新视图 VWFE_TASK去掉 union TWFE_TASK_BAK 的部分,原因是因为后面做了流程预演导致的问题转载于:https://blog.51cto.com/iderun/1602828

swiftswift3.0自己封装的快速构建页面的方法
//#param mark 控件 func creatLabel(frame:CGRect,text:String,textColor:UIColor,textFont:CGFloat,textAlignment:NSTextAlignment) -> UILabel { let label UILabel.init(frame: frame) label.text text label.textColor textColor label.font UIFont.systemFont(of…
Google是如何做Code Review的?| CSDN原力计划
作者 | 帅昕 xindoo 编辑 | 屠敏出品 | CSDN 博客我和几个小伙伴一起翻译了Google前一段时间放出来的Google’s Engineering Practices documentation(https://github.com/google/eng-practices),翻译后的GitHub仓库:https://gith…

从FFmpeg 4. 2源码中提取dshow mjpeg code步骤
之前在https://blog.csdn.net/fengbingchun/article/details/103735560 中介绍过在Windows上通过vs2017编译FFmpeg源码进行单步调试的步骤,为了进一步熟悉FFmpeg这里以提取FFmpeg dshow mjpeg源码为例介绍其实现过程及注意事项: FFmpeg是用C实现的&…

ControlButton按钮事件
#ifndef __HControlButton_H__#define __HControlButton_H__#include "cocos2d.h"#include "cocos-ext.h"USING_NS_CC;USING_NS_CC_EXT; //用于标识当前按钮的状态typedef enum{ touch_begin, touch_down, touch_up,}tagForTouch;class HControlB…