命令模式.ppt_第1页
命令模式.ppt_第2页
命令模式.ppt_第3页
命令模式.ppt_第4页
命令模式.ppt_第5页
已阅读5页,还剩36页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

命令模式 将把封装带到一个全新的境界:把方法调用 (method invocation) 封装起来 通过封装方法调用,可以把运算块包装成形 通过封装方法调用,也可以做一些很聪明的事情, 例如记录日志,或者重复使用这些封装来实现撤销 (undo) 封装调用 巴斯特家电自动化公司 n设计一个家电自动化遥控器的api n附上一个创新控制器的原型以供研究 n这个遥控器具有7个可编程的插槽(每个都可以指定到一个 不同的家电装置) n每个插槽都有对应的开关按钮 n这个遥控器还具备一个整体的撤销按钮 n在光盘里附上有一组java类,这些类是由多家厂商开 发出来的,用来控制家电自动化装置,例如电灯、风 扇、热水器、音响设备和其他类似的可控制装置 n希望能够创建一组控制遥控器的api,让每个插槽都 能够控制一个或一组装置 让硬件解脱!让我们看看这个遥控器 看一下厂商的类 思考 目前有一个附着开和关按钮的简单遥控器,还有一套 五花八门的厂商类 有许多类都具备on()和off()方法,除此之外,还有一 些方法像是dim(), settemperature(), setvolumn(), setdirection() 要把它看成分离的关注点:遥控器应该知道如何解读 按钮被按下的动作,然后发出正确的请求,但是遥控 器不需知道这些家电自动化的细节,或者如何打开热 水器 但如果遥控器很笨,只知道如何做出一般的要求,那 又怎能设计出让这个遥控器能够调用一些诸如打开电 灯或车库门的动作? 不必让遥控器知道太多厂商类的细节 不想让遥控器包含一大堆if语句,例如“if slot1=light, then light.on(), else if slot1=hottub then hottob.jetson() ” 如果这样设计的话,只要有新的厂商类进来,就必须修 改代码 命令模式可将“动作的请求者”从“动作的执行者”对象中解 耦,请求者可以是遥控器,而执行者对象就是厂商类其 中之一的实例 在设计中采用“命令对象”。利用它,把请求(例如打开电 灯)封装成一个特定对象(例如客厅电灯对象)。 如果对每个按钮都存储一个命令对象,那么当按钮被按 下时,就可以请命令对象做相关的工作 遥控器并不需要知道工作内容是什么,只要有个命令对 象能和正确的对象沟通 使用模式,能够创建一个api,将这些命令对象加载到按 钮插槽,让遥控器的代码尽量保持简单。而把家电自动 化的工作和进行该工作的对象一起封装在命令对象中 这个模式可以同时设计“撤销按钮” 餐厅 餐厅的角色和职责 一张订单封装了准备餐店的请求 把订单想象成一个用来请求准备餐点的对象,和一般的 对象一样,订单对象可以被传递:从女招待传递到订单 柜台,或者从女招待传递到接替下一班的女招待 订单的接口只包含一个方法,也就是orderup() 这个方法封装了准备餐点所需的动作 订单内有一个到“需要进行准备工作的对象”(也就是厨师 )的引用 这一切都被封装起来,所以女招待不需要知道订单上有 什么,也不需要知道是谁来准备餐点;她只需要将订单 放到订单窗口,然后喊一声“订单来了”就可以了 女招待的工作是接受订单,然后调用订单的orderup()方 法 女招待的工作很简单:接下顾客的订单,继续帮助下一 个顾客,然后将一定数量的订单放到订单柜台,并调用 orderup()方法,让人来准备餐点 女招待其实不必担心订单的内容是什么,或者由谁来准 备餐点 她只需要知道,订单有一个orderup()方法可以调用 现在,一天内,不同的顾客有不同的订单,这会使得女 招待的takeorder()方法被传入不同的参数 女招待知道所有的订单都支持orderup()方法,任何时候 她需要准备餐点时,调用这个方法 快餐厨师具备准备餐点的知识 快餐厨师是一种对象,他真正知道如何准备餐点 一旦女招待调用orderup()方法,快餐厨师就接 手,实现需要创建餐点的所有方法 请注意,女招待和厨师之间是彻底的解耦:女招 待的订单封装了餐点的细节,她只要调用每个订 单的方法即可,而厨师看了订单就知道该做些什 么餐点;厨师和女招待之间从来不需要直接沟通 重点 把餐厅想成是oo设计模式的一种模型,而这个模型允许 将“发出请求的对象”和“接受与执行这些请求的对象”分隔 开来 对于遥控器api,我们需要分隔开“发出请求的按钮代码” 和“执行请求的厂商特定对象” 万一遥控器的每个插槽都持有一个像餐厅订单那样的对 象,会怎么样? 那么,当一个按钮被按下,只要调用该对象的orderup() 方法,电灯就开了,而遥控器不需要知道事情是怎么发 生的,也不需要知道涉及哪些对象 现在我们就把餐厅的对话换成命令模式 从餐厅到命令模式 加载调用者 客户创建一个命令对象 客户利用setcommand()将命令对象储存在调 用者中 稍后客户要求调用者执行命令。请注意: 一旦命令被加载到调用者,该命令可以被使用 并丢弃,或者可以被保留下来并使用许多次 连连看 餐厅命令模式 女招待command 快餐厨师execute() orderup()client 订单invoker 顾客receiver takeorder() setcommand() 第一个命令对象 实现命令接口(餐厅例子中是orderup(),现在改 为惯用名称execute) public interface command public void execute(); 实现一个打开电灯的命令 现在,假设想实现一个打开电灯的命令。根 据厂商所提供的类 public class lightoffcommand implements command light light; public lightoffcommand(light light) this.light = light; public void execute() light.off(); 使用命令对象 让我们把这一切简化:假设我们有一个遥控器,它只有一个 按钮和对应的插槽,可以控制一个装置 public class simpleremotecontrol command slot; public simpleremotecontrol() public void setcommand(command command) slot = command; public void buttonwaspressed() slot.execute(); 遥控器使用的简单测试 public class remotecontroltest public static void main(string args) simpleremotecontrol remote = new simpleremotecontrol(); light light = new light(); lightoncommand lighton = new lightoncommand(light); remote.setcommand(lighton); remote.buttonwaspressed(); 练习 实现garagedooropencommand 修改remotecontroltest 定义命令模式 命令模式将“请求”封装成对象,以便使用不同的请 求、队列或者日志来参数化其他对象 命令模式也支持可撤销的操作 一个命令对象通过在特定接收者上绑定一组动作来 封装一个请求 命令对象将动作和接收者包进对象中 这个对象只暴露出一个execute()方法,当此方能被 调用的时候,接收者就会进行这些动作 从外面来看,其他对象不知道究竟哪个接收者进行 了哪些动作,只知道如果调用execute()方法,请求 的目的就能达到 利用命令来参数化对象的一些例子 再回到餐厅,一整天下来,女招待参数化许多订单 在简单遥控器中,我们先用一个“打开电灯”命令加 载按钮插槽,稍后又将命令替换成为另一个“打开 车库门”命令 就和女招待一样,遥控器插槽根本不在乎所拥有的 是什么命令对象,只要该命令对象实现了 command接口就可以了 类图 在简单遥控器(simpleremote) 中所做的一样 需要提供一个方法,将命令指定到插槽 实际上,我们有7个插槽,每个插情都具备“开“ 和“关“按钮,所以我们可以用类似方式,把命令 指定给遥控器,像这样 oncommands0=oncommand; offcommands0=offcommand; 将命令指定到插槽 将遥控器的每个插槽,对应到一个命令这样就让 遥控器变成“调用者” 当按下按钮,相应命令对象的execute()方法就会 被调用,其结果就是,接受者(例如:电灯、天 花板电扇、音响)的动作被调用 实现遥控器 remotecontrol 实现命令 lightoffcommand stereoonwithcdcommand 逐步测试遥控器 remoteloader 撤销的功能 当命令支持撤销时,该命令就必须提供和 execute()方法相反的undo()方法 不管execute()刚才做什么,undo()都会倒转过来 在各个命令中加入undo()之前,我们必须先在 command接口中加入undo()方法 public interface command public void execute(); public void undo(); 从lightoncommand开始下手:如果lightoncommand 的execute()方法被调用,那么最后被调用的是on()方法 undo()需要调用off()方法进行相反的动作 lightoncommand lightoffcommand 要加上对撤销按钮的支持,必须对遥控器类做一些小修 改 我们打算这么做:加入一个新的实例变量,用来追踪最 后被调用的命令,然后,不管何时撤销按钮被按下,我 们都可以取出这个命令并调用它的undo()方法 remotecontrolwithundo qa remoteloader 使用状态实现撤销 实现电灯的撒销是有意义的,但也实在是太容易了 通常,想要实现撤销的功能,需要记录一些状态 让我们试一个更有趣的例子,比方说厂商类中的天花 板上的吊扇 吊扇允许有多种转动速度,当然也允许被关闭 ceilingfan 加入撤销到吊扇的命令类 让我们把撤销加入天花板吊扇的诸多命令中 需要追踪吊扇的最后设置速度,如果undo()方法 被调用了,就要恢复成之前吊扇速度的设置值 ceilingfanhighcommand 如何实现low(低速)、medium(中速)、off(关闭) 准备测试天花板吊扇 remoteloader 每个遥控器都需具备“party模式“ 如果拥有了一个遥控器,却无法光凭按下一个按 钮,就同时能弄暗灯光、打开音响和电视、设置 好dvd. 并让热水器开始加温,那么要这个遥控 器还有什么意义? 制造一种新的命令,用来执行其他一堆命令 ,而不只是执行一个命令 macrocommand public class macrocommand implements command command commands; public macrocommand(command commands) mands = commands; public void execute() for (int i = 0; i commands.length; i+) commandsi.execute(); 使用宏命令 先创建想要进入宏的命令集合: light light = new light(“living room“); tv tv = new tv(“living room”); stereo stereo = new stereo (“living room“); hottub hottub = new hottub(); lightoncommand lighton = new lightoncommand(light); stereooncommand stereoon = new stereooncommand(stereo); tvoncommand tvon = new tvoncommand(tv); hottuboncommand hottubon = new hottuboncommand(hottub); 按下来创建两个数组,其中一个用来记录开启命 令,另一个用来记录关闭命令,并在数组内放入 对应的命令: command partyon = lighton, stereoon, tvon, hottubon; command partyoff = lightoff, stereooff, tvoif, hottuboff; macrocommand partyonmacro = new macrocommand(partyon); macrocommand partyoffmacro = new macrocommand(partyoff); 然后将宏命令指定给我们所希望的按钮 remoteco

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论