基本介绍

在软件设计中,我们经常需要向某些对象发送一些请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需要在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来设计,使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活。

命令模式(Command Pattern)可以对发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。

命令模式将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。

模式结构

  • Invoker:调用者,发送命令

  • Receiver:接收者,接收命令

  • Command:抽象命令类,定义了所有的命令

  • ConcreteCommand:具体命令类,调用接收者的操作

举例说明

现有许多家电(电灯、电视机、空调....),每个家电都有自己的控制装置,如果需要控制它们,需要逐个开启、逐个关闭,这时候,如果有一个万能遥控器(如下如所示),操作不同的家电只需要按对应的按钮即可,如何使用命令模式实现?

1、创建电灯的命令接收者

public class LightReceiver {
public void on() {
System.out.println("电灯打开了");
} public void off() {
System.out.println("电灯关闭了");
}
}

2、创建抽象的命令接口

public interface Command {
/**
* 执行命令
*/
void execute(); /**
* 撤销命令
*/
void undo();
}

3、创建电灯的开启、关闭命令类,实现命令接口

public class LightOnCommand implements Command {
private LightReceiver lightReceiver; public LightOnCommand(LightReceiver lightReceiver) {
this.lightReceiver = lightReceiver;
} @Override
public void execute() {
lightReceiver.on();
} @Override
public void undo() {
lightReceiver.off();
}
}
public class LightOffCommand implements Command {
private LightReceiver lightReceiver; public LightOffCommand(LightReceiver lightReceiver) {
this.lightReceiver = lightReceiver;
} @Override
public void execute() {
lightReceiver.off();
} @Override
public void undo() {
lightReceiver.on();
}
}

4、创建空的命令类,用于初始化按钮

public class NullCommand implements Command {
@Override
public void execute() { } @Override
public void undo() { }
}

5、创建命令调用者

public class RemoteController {
/**
* 操作对象的个数
*/
private static final int COUNT = 5;
/**
* 开启命令组
*/
Command[] onCommands;
/**
* 关闭命令组
*/
Command[] offCommands;
/**
* 执行撤销的命令
*/
Command undoCommand; /**
* 初始化
*/
public RemoteController() {
onCommands = new Command[COUNT];
offCommands = new Command[COUNT];
for (int i = 0; i < COUNT; i++) {
onCommands[i] = new NullCommand();
offCommands[i] = new NullCommand();
}
} /**
* 设置按钮
*/
public void setCommand(int no, Command onCommand, Command offCommand) {
onCommands[no] = onCommand;
offCommands[no] = offCommand;
} /**
* 按下开按钮
*/
public void pressOnButton(int no) {
onCommands[no].execute();
//记录按钮,以便撤销
undoCommand = onCommands[no];
} /**
* 按下关按钮
*/
public void pressOffButton(int no) {
offCommands[no].execute();
//记录按钮,以便撤销
undoCommand = offCommands[no];
} /**
* 按下撤销按钮
*/
public void pressUndoButton(int no) {
if (undoCommand != null) {
undoCommand.undo();
}
}
}

6、测试类

public class Client {
@Test
public void testLight() {
//创建命令接收者
LightReceiver lightReceiver = new LightReceiver();
//创建电灯的一组操作(开和关)
LightOnCommand lightOnCommand = new LightOnCommand(lightReceiver);
LightOffCommand lightOffCommand = new LightOffCommand(lightReceiver);
//创建命令调用者
RemoteController remoteController = new RemoteController();
//设置命令
remoteController.setCommand(0, lightOnCommand, lightOffCommand);
//执行命令
System.out.println("----按下开灯按钮----");
remoteController.pressOnButton(0);
System.out.println("----按下关灯按钮----");
remoteController.pressOffButton(0);
System.out.println("----按下撤销按钮----");
remoteController.pressUndoButton(0);
}
}

7、运行结果

----按下开灯按钮----
电灯打开了
----按下关灯按钮----
电灯关闭了
----按下撤销按钮----
电灯打开了

8、如果再添加一个电视机,不需要改动任何已有的代码,添加 TvReceiverTvOnCommandTvOffCommand 这几个类即可。

模式分析

最新文章

  1. mysql事务
  2. #pg学习#postgresql的安装
  3. ios中常用数据类型相互转换
  4. CGRectGet系列
  5. uva 11538 Chess Queen&lt;计数&gt;
  6. 基于jmeter,jenkins,ANT接口,性能测试框架
  7. 团队作业4——第一次项目冲刺(Alpha版本)1st day
  8. jstl c标签 ”test does not support runtime expressions“
  9. EasyUI整合篇
  10. 简单的ld链接脚本学习
  11. MyBatis 源码分析 - SQL 的执行过程
  12. P3261 [JLOI2015]城池攻占
  13. [pat]数素数
  14. fabric-ca-server
  15. Unity3D笔记二十 多媒体与网络
  16. 关于apicloud图片缓存
  17. javascript 图片滚动
  18. laravel 使用 vue (gulp)
  19. Beautiful Year(拆分四位数)
  20. Django Ajax学习二之csrf跨站请求伪造

热门文章

  1. CVPR 2019细粒度图像分类竞赛中国团队DeepBlueAI获冠军 | 技术干货分享
  2. Jmeter4.0接口测试之断言实战(六)
  3. 自适应线性神经网络Adaline
  4. 纯css实现图片或者页面变灰色
  5. iOS 内置图片瘦身
  6. [codevs]1250斐波那契数列&lt;矩阵乘法&amp;快速幂&gt;
  7. git原理,git命令使用详解,github使用 --有此图文并茂原来如此简单
  8. 使用jdbc实现简单的mvc模式的增删改查
  9. 牛客寒假基础集训营 | Day1 G-eli和字符串
  10. PTA | 1009说反话(20分)