OOP设计模式[JAVA]——04命令模式
命令模式
命令模式的意图
命令模式属于对象的行为模式。别名又叫:Action或Transaction。
命令模式把一个请求或者操作封装到一个对象中。命令模式允许系统使用不同的请求把客户端参数化,对请求排队或者记录日志,可以提供命令的撤销和恢复功能。
命令模式的结构
命令模式的参与者
- Command
——声明一个给所有具体命令类的抽象接口。这是一个抽象角色,通常由一个Java接口或Java抽象类实现。 - ConcreteCommand
——将一个接收者对象绑定于一个动作
——调用接收者相应的操作,以实现execute - Client
——创建一个具体命令对象并设定它的接收者 - Invoker
——负责调用命令对象执行请求。 - Receiver
——知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。
命令模式的活动序列
- 客户端创建了一个ConcreteCommand对象,并指明了接收者。
- 请求者对象保存了ConcreteCommand对象。
- 请求者对象通过调用action()方法发出请求。如果命令是撤消的,那么ConcreteCommand保存了调用execute()方法之前的状态。
- ConcreteCommand对象调用接收的一方的方法执行请求。
命令模式的使用场景
家电遥控器,该遥控器的原型如下:
- 有7个可编程的插槽(每一个都可以指定到一个不同的家电装置)
- 每个插槽都有对应的开关按钮
- 具备一个整体的撤销按键
下面我们来看看最简单的实现。
Command:抽象命令接口
/**
* 抽象接口 Command
* @author nick
*
*/
public interface Command {
public void execute(); //非常简单,只需要一个方法:execute()
}
ConcreteCommand:具体命令类
/**
* 具体命令类
* @author nick
*
*/
public class LightOnCommand implements Command { //构造器传入了接收对象,以便让这个命令控制,然后记录在实例变量中。
//一旦调用execute()方法,就由这个对象成为接收者,负责接收请求
public LightOnCommand(Light light) {
super();
this.light = light;
} @Override
public void execute() {
// 这个execute()方法调用接收对象的on()方法
light.on();
} Light light;
}
Client:客户端
/**
* 遥控器测试类------>客户端
* @author nick
*
*/
public class RemoteControlTest { /**
* @param args
*/
public static void main(String[] args) {
// 遥控器就是调用者,会传入一个命令对象,可以用来发出请求
SimpleRemoteControl remote = new SimpleRemoteControl();
//创建一个电灯对象,此对象就是请求的接收者
Light light = new Light();
//创建一个命令,然后将接收者传递给它
LightOnCommand lightOn = new LightOnCommand(light); remote.setCommand(lightOn); //把命令传给调用者
remote.buttonWasPressed(); //模拟遥控器的按钮按下动作
} }
invoker:调用者
/**
* 遥控器类------>调用者
*
* @author nick
*/
public class SimpleRemoteControl {
Command slot; //有一个插槽持有命令,而这个命令控制着一个装置 public SimpleRemoteControl() {
} public void setCommand(Command command) { //用来设置插槽控制的命令
slot = command;
} public void buttonWasPressed() { //遥控器按钮按下时,使得当前命令衔接插槽
slot.execute();
}
}
Receiver:接收者
/**
* 电灯对象------>接收者
* @author nick
*
*/
public class Light {
int level; public Light() {} 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;
}
}
模拟结果输出如下:
Light is on
以上只是单个命令的操作,如果我们需要添加一个LightOff的命令呢,那该怎么办?看下面:
/**
* 具体命令类---->关闭电灯
* @author nick
*
*/
public class LightOffCommand implements Command { //构造器传入了接收对象,以便让这个命令控制,然后记录在实例变量中。
//一旦调用execute()方法,就由这个对象成为接收者,负责接收请求
public LightOffCommand(Light light) {
super();
this.light = light;
} @Override
public void execute() {
// 这个execute()方法调用接收对象的off()方法
light.off();
} Light light;
}
/**
* 遥控器测试类------>客户端
* @author nick
*
*/
public class RemoteControlTest {
/**
* @param args
*/
public static void main(String[] args) {
// 遥控器就是调用者,会传入一个命令对象,可以用来发出请求
SimpleRemoteControl remote = new SimpleRemoteControl();
//创建一个电灯对象,此对象就是请求的接收者
Light light = new Light();
//创建一个命令,然后将接收者传递给它
LightOnCommand lightOn = new LightOnCommand(light);
LightOffCommand lightOff = new LightOffCommand(light); //添加LightOff命令 remote.setCommand(lightOn); //把命令传给调用者
remote.setCommand(lightOff);
remote.buttonWasPressed(); //模拟遥控器的按钮按下动作
}
}
好了,其他几个控制命令,可以按这个去添加即可。但是我们别忘了,Command模式不是说还可以提供撤消和恢复功能吗,那这个功能我们又该如何实现呢?
因为每个控制按钮都需要实现撤消功能,所以我们要在抽象命令的接口中定义该撤消功能的方法:
/**
* 抽象接口 Command
* @author nick
*
*/
public interface Command {
public void execute(); // 非常简单,只需要一个方法:execute()
public void undo(); // 添加一个撤消方法
}
具体命令类的实现:
/**
* 具体命令类
* @author nick
*
*/
public class LightOnCommand implements Command { //构造器传入了接收对象,以便让这个命令控制,然后记录在实例变量中。
//一旦调用execute()方法,就由这个对象成为接收者,负责接收请求
public LightOnCommand(Light light) {
super();
this.light = light;
} @Override
public void execute() {
// 这个execute()方法调用接收对象的on()方法
light.on();
} @Override
public void undo() {
// 实现抽象命令中的撤消功能,该撤消动作就是电灯对象的上一个动作(light off)
System.out.println("Ready to undo---->");
light.off();
} Light light;
}
/**
* 具体命令类---->关闭电灯
* @author nick
*
*/
public class LightOffCommand implements Command { //构造器传入了接收对象,以便让这个命令控制,然后记录在实例变量中。
//一旦调用execute()方法,就由这个对象成为接收者,负责接收请求
public LightOffCommand(Light light) {
super();
this.light = light;
} @Override
public void execute() {
// 这个execute()方法调用接收对象的off()方法
light.off();
} public void undo() {
// 实现抽象命令中的撤消功能,该撤消动作就是电灯对象的上一个动作(light on)
System.out.println("Ready to undo---->");
light.on();
} Light light;
}
调用者类
/**
* 遥控器类------>调用者
*
* @author nick
*/
public class SimpleRemoteControl {
Command onCommand;
Command offCommand;
Command undoCommand; public SimpleRemoteControl() {
} public void setCommand(Command onCom, Command offCom) {//用来设置插槽控制的命令
onCommand = onCom;
offCommand = offCom;
} public void onButtonWasPressed() { //开电灯按钮按下,执行打开电灯命令
onCommand.execute();
undoCommand = onCommand;
} public void offButtonWasPressed() { //关电灯按钮按下,执行关闭电灯命令
offCommand.execute();
undoCommand = offCommand;
} public void undoButtonWasPressed() { //撤消按钮按下,执行撤消动作
undoCommand.undo();
}
}
客户端
/**
* 遥控器测试类------>客户端
* @author nick
*
*/
public class RemoteControlTest {
/**
* @param args
*/
public static void main(String[] args) {
// 遥控器就是调用者,会传入一个命令对象,可以用来发出请求
SimpleRemoteControl remote = new SimpleRemoteControl();
//创建一个电灯对象,此对象就是请求的接收者
Light light = new Light();
//创建一个命令,然后将接收者传递给它
LightOnCommand lightOn = new LightOnCommand(light);
LightOffCommand lightOff = new LightOffCommand(light); //添加LightOff命令 remote.setCommand(lightOn, lightOff); remote.onButtonWasPressed(); //模拟遥控器的按钮按下动作
remote.undoButtonWasPressed();
System.out.println("++++++++++++++++++++");
remote.offButtonWasPressed();
remote.undoButtonWasPressed();
}
}
测试结果如下:
Light is on
Ready to undo---->
Light is off
++++++++++++++++++++
Light is off
Ready to undo---->
Light is on
命令模式的效果
Command模式有以下效果:
- Command模式将调用操作的对象与知道如何实现该操作的对象解耦
- Command是头等的对象。它们可像其他的对象一样被操作和扩展
- 可将多个命令装配成一个复合命令。
- 增加新的Command很容易,无需改变已有的类
命令模式的实现
实现command模式须考虑的问题有如下:
- 一个命令对象应达到何种智能程度 命令对象的能力可大可小。一个极端是它仅确定一个接收者和执行该请求的动作。另一个极端是它自己实现所有功能,根本不需要接收对象。当需要定义与已有的类无关的命令,当没有合适的接收者,或当一个命令隐式地知道它的接收者时,可以使用后一极端方式。在这两个极端间的情况是命令对象有足够的信息可以动态的找到它们的接收者。
- 支持取消(undo)和重做(redo) 如果Command提供方法逆转它们操作的执行(undo),就可支持取消和重做功能。为达到这个目的,ConcreteCommand类可能需要存储额外的状态信息。这个状态包括:
- 接收者对象,它真正执行处理该请求的各操作。
- 接收者上执行操作的参数
- 如果处理请求的操作会改变接收者对象中的某些值,那么这些值也必须先存储起来。接收者还必须提供一些操作,以使该命令可将接收者恢复到它先前的状态。
若应用只支持一次取消操作,那么只需存储最近一次被执行的命令。而若要支持多级的取消和重做,就需要有一个已被执行命令的历史表列(history list),该表列的最大长度决定了取消和重做的级数。历史表列存储了已被执行的命令序列。向后遍历该表列并逆向执行( r e v e r s e - e x e c u t i n g )命令是取消它们的结果;向前遍历并执行命令是重执行它们。有时可能不得不将一个可撤消的命令在它可以被放入历史列表中之前先拷贝下来。这是因为执行原来的请求的命令对象将在稍后执行其他的请求。如果命令的状态在各次调用之间会发生变化,那就必须进行拷贝以区分相同命令的不同调用。
- 避免取消操作过程中的错误积累
OOP设计模式[JAVA]——04命令模式的更多相关文章
- Java设计模式学习记录-命令模式
前言 这次要介绍的是命令模式,这也是一种行为型模式.最近反正没有面试机会我就写博客呗,该投的简历都投了.然后就继续看书,其实看书也会给自己带来成就感,原来以前不明白的东西,书上已经给彻底的介绍清楚了, ...
- java 之 命令模式(大话设计模式)
命令模式,笔者一直以为当我们开发的过程中基本上很难用到,直到维护阶段或者重构阶段,我们会发现有些撤销命令和追加命令比较频繁时,自然而然就用到命令模式. 先看下类图 大话设计模式-类图 简单说下类图,最 ...
- JAVA设计模式之:命令模式
*通常情况下:行为请求者与实现者通常呈现一种高度耦合状态.有时要对行为进行变更处理处理.高度耦合方式就显得不合适. * 将行为请求者与行为实现者解耦,将一组行为抽象为对象.实现二者之间的松耦合. 这就 ...
- java设计模式-----23、命令模式
概念: Command模式也叫命令模式 ,是行为设计模式的一种.Command模式通过被称为Command的类封装了对目标对象的调用行为以及调用参数. 命令模式(Command Pattern)是一种 ...
- 《JAVA设计模式》之命令模式(Command)
在阎宏博士的<JAVA与模式>一书中开头是这样描述命令(Command)模式的: 命令模式属于对象的行为模式.命令模式又称为行动(Action)模式或交易(Transaction)模式. ...
- 重学 Java 设计模式:实战命令模式「模拟高档餐厅八大菜系,小二点单厨师烹饪场景」
作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 持之以恒的重要性 初学编程往往都很懵,几乎在学习的过程中会遇到 ...
- Java设计模式系列之命令模式
命令模式(Command)的定义 将一个请求封装为一个对象,从而可用不同的请求对客户进行参数化:对请求排队或记录日志,以及支持可撤销的操作,将”发出请求的对象”和”接收与执行这些请求的对象”分隔开来. ...
- JAVA设计模式之【命令模式】
命令模式 为了降低耦合度,将请求的发送者和接收者解耦 发送请求的对象只需要哦知道如何发送请求,而不必知道如何完成请求 对请求排队 记录请求日志 支持撤销操作 核心在于引入命令类 角色 抽象命令类Com ...
- Java设计模式(20):命令模式
本文源码:GitHub·点这里 || GitEE·点这里 一.生活场景 1.场景描述 智能电脑的品牌越来越多,由此诞生了一款电脑控制的APP,万能遥控器,用户在使用遥控器的时候,可以切换为自家电视的品 ...
随机推荐
- 【干货】使用EnCase来分析windows 7文件系统------认识元数据记录$MFT,数据恢复
来源:Unit 6: Windows File Systems and Registry 6.1 Windows File Systems and Registry Windows NTFS File ...
- Git GUI可视化操作教程
1.在本地新建版本库 首先,我们打开Git GUI是这样的一个界面,选择第一项,新建版本库. 然后选择你需要进行版本管理的项目路径,我选择了一个LoginDemo的项目. 当你创建了版本库的时候, ...
- 008_MAC 终端使用技巧
一.常用终端命令. <1>reset 的作用很简单——将目前「终端」屏幕上的内容清空,就好像刚刚打开终端一样. <2>如果你在一条终端命令中发现有输入错误的话,那么用 cont ...
- COM和.NET的互操作
组件对象模型的基本知识 基于构件的软件开发日益流行,这里我吧自己在学校时整理的关于COM的一些东西献给大家,供初学者参考.一.组件(COM),是微软公司为了计算机工业的软件生产更加符合 ...
- 【转】java comparator 升序、降序、倒序从源码角度理解
原文链接:https://blog.csdn.net/u013066244/article/details/78997869 环境jdk:1.7+ 前言之前我写过关于comparator的理解,但是都 ...
- php里获取第一个中文首字母并排序
需求里结算首页需要按门店的首字母A-Z排序.我的数据结构原本是这样的: Array ( [0] => Array ( [sid] => 2885842 [recetcstoredpay] ...
- ubuntu16。04LST配置nfs实现服务器和客户端共享文件
NFS(network file system)网络文件系统可以实现不同主机与操作系统之间通过网络进行资源共享,此时一台PC充当服务器,若干台PC充当那客户端,具体如何配置请跟随我的步骤来做 1 下载 ...
- 压缩跟踪Compressive Tracking(转)
这位博主总结的实在太好了,从原理到论文到代码,连论文都不用看:论文:http://blog.csdn.net/zouxy09/article/details/8118360 代码部分:http://b ...
- Python 驱动 MongoDB 示例(PyMongo)
Python 的MongoDB驱动 pymongo ,使用pip Install pymongo安装即可 最近发现网上的很多实例已经过时了,在此自我探究记录下来. 编写一个接口类来支持MongoDB的 ...
- Vue $createElement
const h=this.$createElement; h('span', tag, '内容可以是 ') ..... tag完整的数据对象如下: { // 和`v-bind:class`一样的 ...