博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式学习专栏五--------命令模式
阅读量:6894 次
发布时间:2019-06-27

本文共 6975 字,大约阅读时间需要 23 分钟。

设计模式学习专栏五--------命令模式

场景


设计一个智能遥控器,遥控器上有7个插槽 , 每个插槽(某设备具体供应商)对应两个按钮 on , off ,以及一个全局的撤销操作undo.

较差的实现方式

判断每个插槽对应的具体厂商是谁, 然后做出对应的动作

if(slot1 == Light){    light.on()}else if(slot1 == Hottub){    hottub.on()}else if(slot1 == TV){    tv.on();}...复制代码
  • 出现的问题
    • 遥控器和具体的设备厂商耦合到了一起 , 遥控器需要 认识 某个插槽当前对应设备的厂商
    • 当加入/删除 新的设备厂商时, 当前代码都需要进行改动

如何解决


对象村餐厅的例子

  • 一张订单封装了 准备餐点的请求
  • 女招待的工作是接收订单 , 然后调用订单的OrderUp()方法 , 女招待不需要担心订单的内容是什么, 或者由谁来准备餐点 , 她只需要指导,订单由一个OrderUp()方法可以调用即可.
  • 快餐厨师具有准备餐点的知识 . 他只要看到订单就知道如何准备餐点 . 厨师和女招侍之间从不需要直接沟通.

把餐厅想象成设计模式的一种模型 , 这个模型允许通过**"封装请求的命令"(订单)**将 "发出请求的对象"(女招待, "订单来啦")"接收与执行这些请求的对象"(厨师) 分隔开 .

从餐厅到命令模式

命令模式总览


定义: 将请求封装成对象(订单),将发出请求的对象(服务员/按钮)和执行请求的对象(厨师/具体供应商)解耦 , 也可以支持撤销操作

  • 类图

  • 模式的理解

    • 角色

      • 封装请求的命令对象(订单) : 一个命令对象通过在特定接收者上绑定一组动作来封装一个请求 receiver.action1(), 该对象之暴露一个execute()方法, 当此方法被调用时, 接收者就会进行对应的动作 . 从女招待的角度来看, 它不需要知道具体哪个 接收者进行了什么动作,只知道如果调用execute()方法 , 请求的目的就能达到了
      • 发出请求的对象(女招待) : ①负责接收命令对象 ②在合适的时候调用命令对象的execute()方法
      • 执行请求的对象(厨师) : 真正执行请求的接收者
    • 细节

      • "撤销操作" 只需在Invocker中定义变量Command undoCommand保存撤销操作即可 . 如果要联系撤销, 则可以用的形式存储执行过的命令

        public class LightOnCommand implements Command {	Light light;	public LightOnCommand(Light light) {		this.light = light;	}	public void execute() {		light.on();	}	public void undo() {		light.off();	}}复制代码
        public class RemoteControlWithUndo {	Command[] onCommands;	Command[] offCommands;	Command undoCommand;	//记录上一次命令 	public RemoteControlWithUndo() {		onCommands = new Command[7];		offCommands = new Command[7]; 		Command noCommand = new NoCommand();		for(int i=0;i<7;i++) {			onCommands[i] = noCommand;			offCommands[i] = noCommand;		}		undoCommand = noCommand;	}  	public void setCommand(int slot, Command onCommand, Command offCommand) {		onCommands[slot] = onCommand;		offCommands[slot] = offCommand;	} 	public void onButtonWasPushed(int slot) {		onCommands[slot].execute();		undoCommand = onCommands[slot];	//记录上一次命令	} 	public void offButtonWasPushed(int slot) {		offCommands[slot].execute();		undoCommand = offCommands[slot];	//记录上一次命令	} 	public void undoButtonWasPushed() {		undoCommand.undo();	//执行撤销命令	}}复制代码
      • "Party模式" : 封装一次请求中的批量操作 (按下一个按钮,同时弄暗灯光 , 打开音响和电视,设置好DVD)

        public class MacroCommand implements Command {	Command[] commands; 	public MacroCommand(Command[] commands) {		this.commands = commands;	} 	public void execute() {		for (int i = 0; i < commands.length; i++) {			commands[i].execute();		}	}}复制代码
    • 使用场景

      • 队列请求 (日志安排 , 线程池 , 工作队列)
        • 以线程池为例 , 将线程需要执行的动作封装进Runnable对象中
        • 线程池 以 阻塞队列存储Runnable对象
        • 当线程空闲时 , 从队列中取出Runnable对象 , 并执行Runnable中重写的Run()方法
        • 总结 : 即线程池中的线程不需要知道具体的执行者是谁,干了什么,只需要在空闲时从队列中取出命令对象Runnable并调用run()方法即可
      • 日志请求
        • 当每个命令被执行时, 会被储存在磁盘中
        • 在系统死机后, 重新加载存储的命令,并以准备的次序执行

案例代码部分

  • 命令对象Command

    public interface Command {	public void execute();	public void undo();}复制代码
  • 具体命令对象--开灯

    public class LightOnCommand implements Command {	Light light;	int level;	public LightOnCommand(Light light) {		this.light = light;	} 	public void execute() {        level = light.getLevel();		light.on();	} 	public void undo() {		light.dim(level);	}}复制代码
  • 具体命令对象 --关灯

    public class LightOffCommand implements Command {	Light light;	int level;	public LightOffCommand(Light light) {		this.light = light;	} 	public void execute() {        level = light.getLevel();		light.off();	} 	public void undo() {		light.dim(level);	}}复制代码
  • 设备厂商 -- Receiver

    public class Light {	String location;	int level;	public Light(String location) {		this.location = location;	}	public void on() {		level = 100;		System.out.println("Light is on");	}	public void off() {		level = 0;		System.out.println("Light is off");	}	public void dim(int level) {		this.level = level;		if (level == 0) {			off();		}		else {			System.out.println("Light is dimmed to " + level + "%");		}	}	public int getLevel() {		return level;	}}复制代码
  • 调用者Invoker --远程遥控器

    public class RemoteControlWithUndo {	Command[] onCommands;	Command[] offCommands;	Command undoCommand; 	public RemoteControlWithUndo() {		onCommands = new Command[7];		offCommands = new Command[7]; 		Command noCommand = new NoCommand();		for(int i=0;i<7;i++) {			onCommands[i] = noCommand;			offCommands[i] = noCommand;		}		undoCommand = noCommand;	}  	public void setCommand(int slot, Command onCommand, Command offCommand) {		onCommands[slot] = onCommand;		offCommands[slot] = offCommand;	} 	public void onButtonWasPushed(int slot) {		onCommands[slot].execute();		undoCommand = onCommands[slot];	} 	public void offButtonWasPushed(int slot) {		offCommands[slot].execute();		undoCommand = offCommands[slot];	} 	public void undoButtonWasPushed() {		undoCommand.undo();	}}复制代码
  • 主程序

    public class RemoteLoader {	public static void main(String[] args) {		RemoteControlWithUndo remoteControl = new RemoteControlWithUndo();		Light livingRoomLight = new Light("Living Room");		LightOnCommand livingRoomLightOn =				new LightOnCommand(livingRoomLight);		LightOffCommand livingRoomLightOff =				new LightOffCommand(livingRoomLight);		remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff);		remoteControl.onButtonWasPushed(0);		remoteControl.offButtonWasPushed(0);		System.out.println(remoteControl);		remoteControl.undoButtonWasPushed();	//撤销操作		System.out.println(remoteControl);		//此时应该是开灯状态	}}复制代码
  • 输出结果

    Light is onLight is off------ Remote Control -------[slot 0] headfirst.designpatterns.command.undo.LightOnCommand    headfirst.designpatterns.command.undo.LightOffCommand[slot 1] headfirst.designpatterns.command.undo.NoCommand    headfirst.designpatterns.command.undo.NoCommand[slot 2] headfirst.designpatterns.command.undo.NoCommand    headfirst.designpatterns.command.undo.NoCommand[slot 3] headfirst.designpatterns.command.undo.NoCommand    headfirst.designpatterns.command.undo.NoCommand[slot 4] headfirst.designpatterns.command.undo.NoCommand    headfirst.designpatterns.command.undo.NoCommand[slot 5] headfirst.designpatterns.command.undo.NoCommand    headfirst.designpatterns.command.undo.NoCommand[slot 6] headfirst.designpatterns.command.undo.NoCommand    headfirst.designpatterns.command.undo.NoCommand[undo] headfirst.designpatterns.command.undo.LightOffCommandLight is dimmed to 100%		//撤销操作 ==> 开灯状态------ Remote Control -------[slot 0] headfirst.designpatterns.command.undo.LightOnCommand    headfirst.designpatterns.command.undo.LightOffCommand[slot 1] headfirst.designpatterns.command.undo.NoCommand    headfirst.designpatterns.command.undo.NoCommand[slot 2] headfirst.designpatterns.command.undo.NoCommand    headfirst.designpatterns.command.undo.NoCommand[slot 3] headfirst.designpatterns.command.undo.NoCommand    headfirst.designpatterns.command.undo.NoCommand[slot 4] headfirst.designpatterns.command.undo.NoCommand    headfirst.designpatterns.command.undo.NoCommand[slot 5] headfirst.designpatterns.command.undo.NoCommand    headfirst.designpatterns.command.undo.NoCommand[slot 6] headfirst.designpatterns.command.undo.NoCommand    headfirst.designpatterns.command.undo.NoCommand[undo] headfirst.designpatterns.command.undo.LightOffCommand复制代码

参考

​ 书籍: HeadFirst设计模式

​ 代码参考地址:

转载于:https://juejin.im/post/5c8632fa6fb9a049a712a42e

你可能感兴趣的文章
Thinkpad T430s NVS5400M Ubuntu 12.04安装
查看>>
定时拍照功能
查看>>
[Unity3d]SecurityException报错解决办法
查看>>
SCVMM创建Linux虚拟机模版
查看>>
添加 Pool Member - 每天5分钟玩转 OpenStack(123)
查看>>
NSDECODER v1.0
查看>>
游侠原创:vmware下android-x86-4.4-RC1体验
查看>>
OpenMNS--管理网络的绝好工具
查看>>
ORACLE LINUX 6.1安装过程
查看>>
iPhone/Mac Objective-C内存管理原理
查看>>
整理Silverlight资源列表(三)-SL实际运用案例
查看>>
02-BGP选路原则和属性详解--weight
查看>>
7.[数据结构和算法分析笔记]词典 Dictionary
查看>>
CCNP精粹系列之八----帧中继全网拓扑试验配置
查看>>
Lync升级S4B秘籍,So Easy!!!
查看>>
SpringBoot整合mybatis、shiro、redis实现基于数据库的细粒度动态权限管理系统实例...
查看>>
android用户界面-组件Widget-进度条ProgressBar
查看>>
猜字谜小游戏编程
查看>>
【OneNote Mobile】 如何处理便签内容的格式?
查看>>
Algeco Scotsman将召开2016年第三季度业绩电话会议
查看>>