【韩老师设计模式8】模板方法和命令模式,ConfigurableApplicationContext,JdbcTemplate
模式划分
行为型 模式(10种)
责任链
- 模拟618电商 大促销 期间,项目上线 流程 多级负责人 审批 场景
命令
- 模拟高档餐厅,八大菜系,小二点单 厨师烹饪 场景
迭代器
- 模拟公司 组织 架构树 结构关系,深度迭代 遍历 人员 信息 输出场景
中介者
- 按照Mybatis 原理,手写 ORM框架,给JDBC方式操作数据库,增加多个中介者 场景
备忘录
- 模拟互联网 系统上线过程中,配置文件回滚 场景
观察者
- 模拟类似 小客车 指标 摇号过程,监听消息 通知用户中签 场景
状态
- 模拟系统营销活动,状态流程 审核发布上线 场景
策略
- 模拟多种 营销类型 优惠券,折扣金额 计算策略 场景
模板方法
- 模拟爬虫 各类电商商品,生成营销推广 海报场景
- 抽奖流程 标准化,模板模式
访问者
- 模拟家长 与 校长,对学生 和 老是的 不同视角信息,访问场景。
还有 解释器 模式
责 命 迭 中 解 备 观 状 策 模 访
责 命 中解迭备 观 状 策 模 访
模仿 中解迭备 策责 观状命
- 我先迭一个,你们随意,大概是 我先喝一杯吧。
模板方法
编写制作豆浆的程序,说明如下:
- 制作豆浆的流程 选材—>添加配料—>浸泡—>放到豆浆机打碎
- 通过添加不同的配料,可以制作出不同口味的豆浆
- 选材、浸泡和放到豆浆机打碎这几个步骤对于制作每种口味的豆浆都是一样的
- 请使用 模板方法模式 完成 (说明: 因为模板方法模式,比较简单, 很容易就
想到这个方案,因此就直接使用, 不再使用传统的方案来引出模板方法模式 )
- 统计 代码的运行时间。也可以用。
基本介绍
- 模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern),
在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法
实现,但调用将以抽象类中定义的方式进行。 - 简单说, 模板方法模式 定义一个操作中的算法的骨架,而将一些步骤延迟到子
类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定
步骤 - 这种类型的设计模式属于行为型模式。
对原理类图的说明-即(模板方法模式的角色及职责)
- AbstractClass 抽象类, 类中实现了模板方法(template),定义了算法的骨
架,具体子类需要去实现 其它的抽象方法operationr2,3,4 - ConcreteClass 实现抽象方法operationr2,3,4, 以完成算法中特点子类的步骤
beat
v.
(反复地)敲,击,打;狠打,猛抽;搅拌,混合;拍动,扇动(翅膀);(心脏)跳动,搏动;击败,战胜;抢……之先,赶在……之前;避开,避免
n.
敲,击;(音乐或诗歌的)强音拍;(经常去或经过的)路线,地点;以之字形航线抢风航行
adj.
<非正式>筋疲力尽,疲惫不堪;垮掉的一代的bean
n.
豆,菜豆,豆科植物;籽实,豆形种子;用于强调丝毫,一点;<旧>脑袋;(Bean)描述Java的软件组件模型(Enterprise Java Bean)
v.
(用某物)击中(某人)头部soya
n.
大豆,[作物]黄豆peanut
英
/ˈpiːnʌt/
n.
花生,花生米;<非正式>很少的钱(peanuts);小片聚苯乙烯泡沫塑料(peanuts)condiment
调味品;佐料
抽象类 指定了流程
//抽象类,表示豆浆
public abstract class SoyaMilk {//模板方法, make , 模板方法可以做成final , 不让子类去覆盖.final void make() {select(); addCondiments();soak();beat();}//选材料void select() {System.out.println("第一步:选择好的新鲜黄豆 ");}//添加不同的配料, 抽象方法, 子类具体实现abstract void addCondiments();//浸泡void soak() {System.out.println("第三步, 黄豆和配料开始浸泡, 需要3小时 ");}void beat() {System.out.println("第四步:黄豆和配料放到豆浆机去打碎 ");}
}
不同的实现类
public class PeanutSoyaMilk extends SoyaMilk {@Overridevoid addCondiments() {System.out.println(" 加入上好的花生 ");}
}SoyaMilk peanutSoyaMilk = new PeanutSoyaMilk();peanutSoyaMilk.make();
----制作花生豆浆----
第一步:选择好的新鲜黄豆 加入上好的花生
第三步, 黄豆和配料开始浸泡, 需要3小时
第四步:黄豆和配料放到豆浆机去打碎
钩子方法
应用实例要求
编写制作豆浆的程序,说明如下:
• 制作豆浆的流程 选材—>添加配料—>浸泡—>放到豆浆机打碎
• 通过添加不同的配料,可以制作出不同口味的豆浆
• 选材、浸泡和放到豆浆机打碎这几个步骤对于制作每种口味的豆浆都是一样的(红
豆、花生豆浆。。。 )
//抽象类,表示豆浆
public abstract class SoyaMilk {//模板方法, make , 模板方法可以做成final , 不让子类去覆盖.final void make() {select(); if(customerWantCondiments()) {addCondiments();}soak();beat();}//添加不同的配料, 抽象方法, 子类具体实现abstract void addCondiments();//钩子方法,决定是否需要添加配料boolean customerWantCondiments() {return true;}
}
重写钩子方法
public class PureSoyaMilk extends SoyaMilk{@Overridevoid addCondiments() {//空实现}@Overrideboolean customerWantCondiments() {//纯豆浆,返回false,不会调用 加配料的方法return false;}}System.out.println("----制作纯豆浆----");SoyaMilk pureSoyaMilk = new PureSoyaMilk();pureSoyaMilk.make();
----制作纯豆浆----
第一步:选择好的新鲜黄豆
第三步, 黄豆和配料开始浸泡, 需要3小时
第四步:黄豆和配料放到豆浆机去打碎
IOC
接口
ConfigurableApplicationContextpublic interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {void refresh() throws BeansException, IllegalStateException;
}
抽象类
- 子类
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {//模板 方法@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory. 里面是抽象方法ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();try {//钩子方法// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);//钩子方法// Initialize other special beans in specific context subclasses.onRefresh();}catch (BeansException ex) {// Propagate exception to caller.throw ex;}finally {resetCommonCaches();}}}}//钩子 方法protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {}protected void onRefresh() throws BeansException {}protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {//两个抽象方法refreshBeanFactory();return getBeanFactory();}//都是 抽象的方法protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;@Overridepublic abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
抽象类的子类
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {//对 抽象方法,进行了实现@Overrideprotected final void refreshBeanFactory() throws IllegalStateException {this.beanFactory.setSerializationId(getId());}@Overridepublic final ConfigurableListableBeanFactory getBeanFactory() {return this.beanFactory;}
}
AbstractRefreshableConfigApplicationContext
- 抽象类类,也是子类,同样实现了。这个两个方法。其子类:
- ClassPathXmlApplicationContext
- FileSystemXmlApplicationContext 提供给别人使用
事项和细节
模板方法模式的注意事项和细节
- 基本思想是: 算法只存在于一个地方,也就是在父类中,容易修改。 需要修改算
法时,只要修改父类的模板方法或者已经实现的某些步骤,子类就会继承这些修改 - 实现了最大化代码复用。 父类的模板方法和已实现的某些步骤会被子类继承而直接
使用。 - 既统一了算法,也提供了很大的灵活性。 父类的模板方法确保了算法的结构保持不
变,同时由子类提供部分步骤的实现。 - 该模式的不足之处:每一个不同的实现都需要一个子类实现,导致类的个数增加,
使得系统更加庞大 - 一般模板方法都加上final关键字, 防止子类重写模板方法.
- 模板方法模式使用场景: 当要完成在某个过程, 该过程要执行一系列步骤 , 这一
系列的步骤基本相同,但其个别步骤在实现时 可能不同,通常考虑用模板方法模
式来处理
命令模式
- 我们买了一套智能家电,有照明灯、风扇、冰箱、洗衣机,我们只要在手机上安装app就
可以控制对这些家电工作。 - 这些智能家电来自不同的厂家,我们不想针对每一种家电都安装一个App,分别控制, 我
们希望只要一个app就可以控制全部智能家电。 - 要实现一个app控制所有智能家电的需要,则每个智能家电厂家都要提供一个统一的接口
给app调用, 这时 就可以考虑使用命令模式。 - 命令模式可将“动作的请求者”从“动作的执行者”对象中解耦出来.
- 在我们的例子中,动作的请求者是手机app,动作的执行者是每个厂商的一个家电产品
基本介绍
命令模式(Command Pattern): 在软件设计中,我们经常需要
向某些对象发送请求,但是并不知道请求的接收者是谁,也不知
道被请求的操作是哪个,
我们只需在程序运行时指定具体的请求接收者即可,此时,可以
使用命令模式来进行设计命名模式使得请求发送者与请求接收者消除彼此之间的耦合,让
对象之间的调用关系更加灵活,实现解耦。在命名模式中,会将一个请求封装为一个对象, 以便使用不同参
数来表示不同的请求(即命名),同时命令模式也支持可撤销的操作。通俗易懂的理解:将军发布命令,士兵去执行。其中有几个角色:
将军(命令发布者)、士兵(命令的具体执行者)、命令(连接将
军和士兵)。
Invoker是调用者(将军), Receiver是被调用者(士兵),
MyCommand是命令,实现了Command接口,持有接收对象Invoker 是调用者角色
Command: 是命令角色,需要执行的所有命令都在这里,可以是接口或抽象类
Receiver: 接受者角色,知道如何实施和执行一个请求相关的操作
ConcreteCommand: 将一个接受者对象与一个动作绑定,调用接受者相应的操作,实现execute
- Invoker(就是下面的遥控器)
- 依赖命令接口
- 命令和 接收者的连接类 ConcreteCommand
- 调用:接收者 Receiver (士兵)
- 命令和 接收者的连接类 ConcreteCommand
- 依赖命令接口
顶层接口
//创建命令接口
public interface Command {//执行动作(操作)public void execute();//撤销动作(操作)public void undo();
}
被调用者(真实的执行者)
public class LightReceiver {public void on() {System.out.println(" 电灯打开了.. ");}public void off() {System.out.println(" 电灯关闭了.. ");}
}
命令类(组合 连接)
- 这里是 开命令,还会有关命令
public class LightOnCommand implements Command {//聚合LightReceiverLightReceiver light;//构造器public LightOnCommand(LightReceiver light) {super();this.light = light;}@Overridepublic void execute() {//调用接收者的方法light.on();}@Overridepublic void undo() {//调用接收者的方法light.off();}
}
- 关 命令类 和 开命令类 相仿。
- 执行:改为关。
- 撤销:改为开。
空命令
/*** 没有任何命令,即空执行: 用于初始化每个按钮, 当调用空命令时,对象什么都不做* 其实,这样是一种设计模式, 可以省掉对空判断*/
public class NoCommand implements Command {@Overridepublic void execute() {}@Overridepublic void undo() {}
}
遥控器
public class RemoteController {// 开 按钮的命令数组Command[] onCommands;Command[] offCommands;// 执行撤销的命令Command undoCommand;// 构造器,完成对按钮初始化public RemoteController() {onCommands = new Command[5];offCommands = new Command[5];for (int i = 0; i < 5; i++) {onCommands[i] = new NoCommand();offCommands[i] = new NoCommand();}}// 给我们的按钮设置你需要的命令public void setCommand(int no, Command onCommand, Command offCommand) {onCommands[no] = onCommand;offCommands[no] = offCommand;}// 按下开按钮public void onButtonWasPushed(int no) { // no 0// 找到你按下的开的按钮, 并调用对应方法onCommands[no].execute();// 记录这次的操作,用于撤销undoCommand = onCommands[no];}// 按下开按钮public void offButtonWasPushed(int no) { // no 0// 找到你按下的关的按钮, 并调用对应方法offCommands[no].execute();// 记录这次的操作,用于撤销undoCommand = offCommands[no];}// 按下撤销按钮public void undoButtonWasPushed() {undoCommand.undo();}}
使用
//使用命令设计模式,完成通过遥控器,对电灯的操作//创建电灯的对象(接受者)LightReceiver lightReceiver = new LightReceiver();//创建电灯相关的开关命令LightOnCommand lightOnCommand = new LightOnCommand(lightReceiver);LightOffCommand lightOffCommand = new LightOffCommand(lightReceiver);//需要一个遥控器RemoteController remoteController = new RemoteController();//给我们的遥控器设置命令, 比如 no = 0 是电灯的开和关的操作remoteController.setCommand(0, lightOnCommand, lightOffCommand);System.out.println("--------按下灯的开按钮-----------");remoteController.onButtonWasPushed(0);System.out.println("--------按下灯的关按钮-----------");remoteController.offButtonWasPushed(0);System.out.println("--------按下撤销按钮-----------");remoteController.undoButtonWasPushed();
- 符合开闭原则,增加电视的开关,RemoteController 无需变化。
JdbcTemplate
- JdbcTemplate 即是:命令调用者 。Invoker是(将军)
- 以 内部类 方式,实现命令接口
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {@Overridepublic void query(String sql, RowCallbackHandler rch) throws DataAccessException {query(sql, new RowCallbackHandlerResultSetExtractor(rch));}
}
- 调查query方法
@Overridepublic <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException {Assert.notNull(sql, "SQL must not be null");//子类,同时又 充当了 士兵的角色class QueryStatementCallback implements StatementCallback<T>, SqlProvider {@Overridepublic T doInStatement(Statement stmt) throws SQLException {ResultSet rs = null;}@Overridepublic String getSql() {return sql;}}//调用 execute ,此方法 是在 jdbcTemplate 实现的return execute(new QueryStatementCallback());}@Overridepublic <T> T execute(StatementCallback<T> action) throws DataAccessException {try {Connection conToUse = con;//doInStatement 就是上面 内部类 实现的一个方法T result = action.doInStatement(stmtToUse);handleWarnings(stmt);return result;}finally {JdbcUtils.closeStatement(stmt);DataSourceUtils.releaseConnection(con, getDataSource());}}
//命令接口
public interface StatementCallback<T> {T doInStatement(Statement stmt) throws SQLException, DataAccessException;
}
- StatementCallback 接口 ,类似命令接口(Command)
- class QueryStatementCallback implements StatementCallback, SqlProvider , 匿名内
部类, 实现了命令接口, 同时也充当命令接收者
- 命令调用者 是 JdbcTemplate , 其中execute(StatementCallback action) 方法中,调
用action.doInStatement 方法. 不同的 实现 StatementCallback 接口的对象,对应不同
的doInStatemnt 实现逻辑
- 另外实现 StatementCallback 命令接口的子类还有 QueryStatementCallback、
不同之处在于,正规的 命令模式:命令接收者(士兵),不会实现命令的。
- 此处的命令调用者(指挥者):还充当了 整合接收者
- ConcreteCommand: 将一个接受者对象与一个动作绑定,调用接受者相应的操作,实现execute
细节
命令模式的注意事项和细节
- 将发起请求的对象与执行请求的对象解耦。发起请求的对象是调用者,调用者只要
调用命令对象的execute()方法就可以让接收者工作,而不必知道具体的接收者对
象是谁、是如何实现的,命令对象会负责让接收者执行请求的动作, 也就是说: ”
请求发起者”和“请求执行者”之间的解耦是通过命令对象实现的,命令对象起到
了纽带桥梁的作用。 - 容易设计一个命令队列。只要把命令对象放到列队,就可以多线程的执行命令
- 容易实现对请求的撤销和重做
- 命令模式不足:可能导致某些系统有过多的具体命令类, 增加了系统的复杂度, 这
点在在使用的时候要注意 - 空命令也是一种设计模式,它为我们省去了判空的操作。在上面的实例中,如果没
有用空命令,我们每按下一个按键都要判空,这给我们编码带来一定的麻烦。 - 命令模式经典的应用场景:界面的一个按钮都是一条命令、 模拟CMD(DOS命令)
订单的撤销/恢复、触发-反馈机制
【韩老师设计模式8】模板方法和命令模式,ConfigurableApplicationContext,JdbcTemplate相关推荐
- 设计模式的理解:命令模式 (Command)
命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式.请求以命令的形式包裹在对象中,并传给调用对象.调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该 ...
- 设计模式心得:三——命令模式
继续设计模式心得体验--命令模式. 命令模式: 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化:对请求排队或记录请求日志,以及支持可撤销的操作. 一般在命令模式中有三个元素,invo ...
- 行为型设计模式(3)—— 命令模式(Command Pattern)
文章目录 1.概述 2.命令模式简单实现 3.命令模式的应用场景和优缺点 4.小结 参考文献 1.概述 使用设计模式可以提高代码的可复用性.可扩充性和可维护性.命令模式(Command Pattern ...
- UVM设计模式 (七)命令模式、三种sequence启动方式、start_item/finish_item、中介模式、virtual sequence
本篇介绍UVM中的sequence,这是UVM中最基础的部分.对于前面介绍的uvm_callback, uvm_visitor等,很少被使用到或者也只有搭建平台的人会使用.不能认为平台的搭建更富有&q ...
- 设计模式系列3-----C++实现命令模式(Command Pattern)
什么是命令模式? GoF的书的定义为:"Command pattern encapsulate request as an object, thereby letting you param ...
- 设计模式---命令模式
考虑这样一种场景:某个方法需要完成某一个行为,但是这个行为的具体实现无法确定,必须等到执行该方法时才可以确定. 具体一点:假设有一个方法是遍历某个数组的数组元素,但是无法确定在遍历的数组的元素的时候如 ...
- (35)23种设计模式研究之六【命令模式】
命令模式 一:定义 将一个请求封装为一个对象(即我们创建的Command对象),从而使你可用不同的请求对客户进行参数化; 对请求排队或记录请求日志,以及支持可撤销的操作. 二:实现 解决的问题 在软件 ...
- 【转】设计模式学习笔记之命令模式
定义:将请求封装成对象,以便使用不同的请求.队列或者日志来参数化其他对象.命令模式支持可撤销等操作. 命令模式将发出请求的对象和执行请求的对象解耦.在被解耦的两者之间是通过命令对象进行沟通的. 案例代 ...
- C++设计模式详解之命令模式解析
C++ 命令模式定义 命令模式将请求封装成对象,以便使用不同的请求,队列或者日志来参数化其他对象. 个人理解: 命令模式,其实实质上就是去耦合的操作,让各个部分尽可能的关联性降低,以便修改或增加某些功 ...
- 《设计模式入门》 19.命令模式
命令模式就是将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开.这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存.传递.调用.增加与管理. 一般命令模式由四类组成: 抽象命令 ...
最新文章
- 独家 | 使用深度神经网络在Oculus Quest上进行准确的手部追踪
- Bzoj1511---OKR-Periods of Words(KMP)
- python下载后如何使用-如何使用Python通过HTTP下载文件
- android backlight
- 数据处理工具(一)——Matplotlib
- 信道和物理媒体的区别
- linux 下环境变量设置
- MATLAB GPU加速
- sql cast()函数
- 浅出Vue 错误处理机制errorCaptured、errorHandler
- poj1258Agri-Net
- C#反编译工具ilspy下载地址
- JavaScript基础
- 新能源汽车电池健康状态及能耗分析
- 高手教你如何从零开始学游戏编程
- Datablau产品之Kubernetes(K8S)部署
- gradient设置上下渐变_CSS3中渐变gradient详解
- vb.net 拓展教程目录
- 路再长也有尽头,别往回走
- Ubuntu音乐播放器
热门文章
- Linux错误 “cp: omitting directory”解决办法
- BZOJ5109 CodePlus 2017大吉大利,晚上吃鸡!(最短路+拓扑排序+bitset)
- 游戏策划笔记:交互分析
- 【计算机视觉40例】案例28:表情识别
- miui10android9,MIUI 10稳定版刚到 基于安卓9的MIUI10 8.9.7开发版也来
- Python编程从入门到实践(第五章练习)
- router禁用443端口
- 网安必备技能||操作系统中间件安全加固手册(附下载地址)
- 中国(西部)云计算中心投产,将成西部规模最大数据中心
- chrome浏览器扩展打包成crx