设计模式读书笔记-----命令模式
2017-09-29 11:27
260 查看
在开发过程中,我可能会需要向某些对象发送一些请求,但是我们不知请求的具体接收者是谁,也不知道被请求的操作是那个,我们只知道在程序运行中指定具体的请求接收者即可。打个比方,电视遥控器,我们只需要知道按那个按钮能够打开电视、关闭电视和换台即可,并不需要知道是怎么开电视、关电视和换台的。对于这种情况,我们可以采用命令模式来进行设计。
一、基本定义
命令模式将请求封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式支持可撤销的操作。
命令模式可以对发送者与接受者完全解耦,发送者与接收者之间并没有直接的联系,发送者只需要知道如何发送请求,不需要关心请求是如何完成了。这就是命令模式,命令模式将方法调用给封装成对象了。
二、模式结构
从上图可以看出命令模式包含如下几个角色:
Command: 抽象命令类
ConcreteCommand: 具体命令类
Invoker: 调用者
Receiver: 接收者
Client:客户类
命令模式的本质就在于将命令进行封装,将发出命令的责任和执行命令的责任分开,发送者只需要知道如何发送命令即可,不需要命令是如何实现的,甚至命令执行是否成功都不需要理会。同时命令模式使得请求也变成了一个对象,它像其他对象一样可以被存储和传递。
三、模式实现
这里以电视机为例:电视机是请求的接受者,遥控器是请求的发送者,遥控器上有一些按钮,不同的按钮对应着不同的操作。在这里遥控器需要执行三个命令:打开电视机、关闭电视机、换台。
UML图:
代码的实现
抽象命令类:Command.java
[java] view
plain copy
/**
* Command命令接口,为所有的命令声明一个接口。所有的命令都应该实现它,从而命令变成对象
*/
public interface Command {
public void execute();
}
电视机类:Television.java
[java] view
plain copy
//电视机类就是命令的接受者:Receiver
public class Television {
public void open(){
System.out.println("打开电视机......");
}
public void close(){
System.out.println("关闭电视机......");
}
public void changeChannel(){
System.out.println("切换电视频道......");
}
}
遥控器类:Controller.java
[java] view
plain copy
//遥控器类:它上面有控制命令操作的3个按钮,然后去让他们3个实现Command命令的接口就可以使用了;
//所以,遥控器就是命令请求的调用者,发出者:Invoker
public class Controller {
//这就是将3个命令进行对象化了!!!
private Command openTVCommand;
//组合引用
private Command closeTVCommand;
private Command changeChannelCommand;
public Controller(Command openTvCommand,Command closeTvCommand,Command changeChannelCommand){
this.openTVCommand = openTvCommand;
this.closeTVCommand = closeTvCommand;
this.changeChannelCommand = changeChannelCommand;
}
//有了引用后就可以调用他的方法进行操作了;
public void open(){
openTVCommand.execute();
}
public void close(){
closeTVCommand.execute();
}
public void change(){
changeChannelCommand.execute();
}
}
遥控器的三个按钮
[java] view
plain copy
//具体的按钮命令:来执行对电视机的打开,
public class OpenTvCommand implements Command{
////所以需要引用接受者类的引用进而操作打开电视
private Television tv;
//引用了所以需要有初始化
//传一个好,这样子只需要在客户端new一次就行了,不然每一个命令都要new一个,肯定不行;
public OpenTvCommand(Television
tv){
this.tv = tv;
}
public void execute() {
tv.open();
}
}
[java] view
plain copy
public class ChangeChannelCommand implements Command{
private Television tv;
//实例变量都需要初始化
public ChangeChannelCommand(Television
tv){
this.tv = tv;
}
public void execute() {
tv.changeChannel();
}
}
[java] view
plain copy
public class CloseTvCommand implements Command{
private Television tv;
public CloseTvCommand(Television
tv){
this.tv = tv;
}
public void execute() {
tv.close();
}
}
客户端:Client.java
[java] view
plain copy
////客户端:使用者(也就是对应我们的测试)
public class Client {
public static void main(String a[])
{
//new 1个电视机
Television tv = new Television();
//new出3个命令对象
Command openCommand = new OpenTvCommand(tv);
Command closeCommand = new CloseTvCommand(tv);
Command changeCommand = new ChangeChannelCommand(tv);
//再new一个遥控器来放上这3个命令
Controller control = new Controller(openCommand,closeCommand,changeCommand);
//可以执行遥控器上的方法(按钮)了:
control.open(); //打开电视机
control.change(); //换频道
control.close(); //关闭电视机
}
}
运行结果
四、模式优缺点
优点
1. 降低了系统耦合度
2. 新的命令可以很容易添加到系统中去。
缺点
使用命令模式可能会导致某些系统有过多的具体命令类。
五、模式使用场景
1.系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
2.系统需要在不同的时间指定请求、将请求排队和执行请求。
3.系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
5.系统需要将一组操作组合在一起,即支持宏命令。
1. 撤销命令
在电视遥控器中,我们还有这样一个按钮,那就是返回。用于切换到上面一个频道中去。在命令模式中也支持撤销操作,在这里我们只需要记录上一个频道,然后将上一个频道传入即可。
在这里将Command进行一个简单的修改:将execute()改为execute(int I );i表示频道,用于进行频道切换。
[java] view
plain copy
/**
* Command命令接口,为所有的命令声明一个接口。所有的命令都应该实现它
*/
public interface Command {
/**
* 为了方便切换频道,这里使用参数i将频道传递
* @param i
*/
public void execute(int i);
}
然后在Controller中添加channelUndo()方法,用于进行频道返回。并且需要进行一些简单的修改。
[java] view
plain copy
public class Controller {
private Command openTVCommand;
private Command closeTVCommand;
private Command changeChannelCommand;
public int nowChannel = 0; //当前频道
public int priorChannel; //前一个频道,用于执行返回操作
public Controller(Command openTvCommand,Command closeTvCommand,Command changeChannelCommand){
this.openTVCommand = openTvCommand;
this.closeTVCommand = closeTvCommand;
this.changeChannelCommand = changeChannelCommand;
}
/**
* 打开电视剧
*/
public void open(){
openTVCommand.execute(0);
}
/**
* 关闭电视机
*/
public void close(){
closeTVCommand.execute(0);
}
/**
* 换频道:只在当前频道递增
*/
public void change(){
priorChannel = nowChannel; //换频道前记录当前频道
nowChannel++; //频道+1
changeChannelCommand.execute(nowChannel);
}
/**
* 频道返回
*/
public void ChannelUndo(){
changeChannelCommand.execute(priorChannel); //将以前的频道传入
//当前频道与前一个频道进行互换
int tempChannel;
tempChannel = priorChannel;
priorChannel = nowChannel;
nowChannel = tempChannel;
}
}
客户端
[java] view
plain copy
public class Client {
public static void main(String a[])
{
Command openCommand,closeCommand,changeCommand;
openCommand = new OpenTvCommand();
closeCommand = new CloseTvCommand();
changeCommand = new ChangeChannelCommand();
Controller control = new Controller(openCommand,closeCommand,changeCommand);
control.open(); //打开电视机
control.change(); //换频道
control.change();
control.ChannelUndo();
control.ChannelUndo();
control.ChannelUndo();
control.close(); //关闭电视机
}
}
运行结果。
1. 命令模式的本质就是将命令对象进行封装打包,将发出命令的责任和执行命令的责任进行割开。
2. 命令模式中发送者只需要知道如何发送请求命令,无须关心命令执行具体过程。
3. 在发送者和接收者两者间是通过命令对象进行沟通的。请求命令本身就当做一个对象在两者间进行传递,它封装了接收者和一组动作。
4. 命令模式支持撤销。
5. 命令模式队列请求和日志请求。
一、基本定义
命令模式将请求封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式支持可撤销的操作。
命令模式可以对发送者与接受者完全解耦,发送者与接收者之间并没有直接的联系,发送者只需要知道如何发送请求,不需要关心请求是如何完成了。这就是命令模式,命令模式将方法调用给封装成对象了。
二、模式结构
从上图可以看出命令模式包含如下几个角色:
Command: 抽象命令类
ConcreteCommand: 具体命令类
Invoker: 调用者
Receiver: 接收者
Client:客户类
命令模式的本质就在于将命令进行封装,将发出命令的责任和执行命令的责任分开,发送者只需要知道如何发送命令即可,不需要命令是如何实现的,甚至命令执行是否成功都不需要理会。同时命令模式使得请求也变成了一个对象,它像其他对象一样可以被存储和传递。
三、模式实现
这里以电视机为例:电视机是请求的接受者,遥控器是请求的发送者,遥控器上有一些按钮,不同的按钮对应着不同的操作。在这里遥控器需要执行三个命令:打开电视机、关闭电视机、换台。
UML图:
代码的实现
抽象命令类:Command.java
[java] view
plain copy
/**
* Command命令接口,为所有的命令声明一个接口。所有的命令都应该实现它,从而命令变成对象
*/
public interface Command {
public void execute();
}
电视机类:Television.java
[java] view
plain copy
//电视机类就是命令的接受者:Receiver
public class Television {
public void open(){
System.out.println("打开电视机......");
}
public void close(){
System.out.println("关闭电视机......");
}
public void changeChannel(){
System.out.println("切换电视频道......");
}
}
遥控器类:Controller.java
[java] view
plain copy
//遥控器类:它上面有控制命令操作的3个按钮,然后去让他们3个实现Command命令的接口就可以使用了;
//所以,遥控器就是命令请求的调用者,发出者:Invoker
public class Controller {
//这就是将3个命令进行对象化了!!!
private Command openTVCommand;
//组合引用
private Command closeTVCommand;
private Command changeChannelCommand;
public Controller(Command openTvCommand,Command closeTvCommand,Command changeChannelCommand){
this.openTVCommand = openTvCommand;
this.closeTVCommand = closeTvCommand;
this.changeChannelCommand = changeChannelCommand;
}
//有了引用后就可以调用他的方法进行操作了;
public void open(){
openTVCommand.execute();
}
public void close(){
closeTVCommand.execute();
}
public void change(){
changeChannelCommand.execute();
}
}
遥控器的三个按钮
[java] view
plain copy
//具体的按钮命令:来执行对电视机的打开,
public class OpenTvCommand implements Command{
////所以需要引用接受者类的引用进而操作打开电视
private Television tv;
//引用了所以需要有初始化
//传一个好,这样子只需要在客户端new一次就行了,不然每一个命令都要new一个,肯定不行;
public OpenTvCommand(Television
tv){
this.tv = tv;
}
public void execute() {
tv.open();
}
}
[java] view
plain copy
public class ChangeChannelCommand implements Command{
private Television tv;
//实例变量都需要初始化
public ChangeChannelCommand(Television
tv){
this.tv = tv;
}
public void execute() {
tv.changeChannel();
}
}
[java] view
plain copy
public class CloseTvCommand implements Command{
private Television tv;
public CloseTvCommand(Television
tv){
this.tv = tv;
}
public void execute() {
tv.close();
}
}
客户端:Client.java
[java] view
plain copy
////客户端:使用者(也就是对应我们的测试)
public class Client {
public static void main(String a[])
{
//new 1个电视机
Television tv = new Television();
//new出3个命令对象
Command openCommand = new OpenTvCommand(tv);
Command closeCommand = new CloseTvCommand(tv);
Command changeCommand = new ChangeChannelCommand(tv);
//再new一个遥控器来放上这3个命令
Controller control = new Controller(openCommand,closeCommand,changeCommand);
//可以执行遥控器上的方法(按钮)了:
control.open(); //打开电视机
control.change(); //换频道
control.close(); //关闭电视机
}
}
运行结果
四、模式优缺点
优点
1. 降低了系统耦合度
2. 新的命令可以很容易添加到系统中去。
缺点
使用命令模式可能会导致某些系统有过多的具体命令类。
五、模式使用场景
1.系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
2.系统需要在不同的时间指定请求、将请求排队和执行请求。
3.系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
5.系统需要将一组操作组合在一起,即支持宏命令。
1. 撤销命令
在电视遥控器中,我们还有这样一个按钮,那就是返回。用于切换到上面一个频道中去。在命令模式中也支持撤销操作,在这里我们只需要记录上一个频道,然后将上一个频道传入即可。
在这里将Command进行一个简单的修改:将execute()改为execute(int I );i表示频道,用于进行频道切换。
[java] view
plain copy
/**
* Command命令接口,为所有的命令声明一个接口。所有的命令都应该实现它
*/
public interface Command {
/**
* 为了方便切换频道,这里使用参数i将频道传递
* @param i
*/
public void execute(int i);
}
然后在Controller中添加channelUndo()方法,用于进行频道返回。并且需要进行一些简单的修改。
[java] view
plain copy
public class Controller {
private Command openTVCommand;
private Command closeTVCommand;
private Command changeChannelCommand;
public int nowChannel = 0; //当前频道
public int priorChannel; //前一个频道,用于执行返回操作
public Controller(Command openTvCommand,Command closeTvCommand,Command changeChannelCommand){
this.openTVCommand = openTvCommand;
this.closeTVCommand = closeTvCommand;
this.changeChannelCommand = changeChannelCommand;
}
/**
* 打开电视剧
*/
public void open(){
openTVCommand.execute(0);
}
/**
* 关闭电视机
*/
public void close(){
closeTVCommand.execute(0);
}
/**
* 换频道:只在当前频道递增
*/
public void change(){
priorChannel = nowChannel; //换频道前记录当前频道
nowChannel++; //频道+1
changeChannelCommand.execute(nowChannel);
}
/**
* 频道返回
*/
public void ChannelUndo(){
changeChannelCommand.execute(priorChannel); //将以前的频道传入
//当前频道与前一个频道进行互换
int tempChannel;
tempChannel = priorChannel;
priorChannel = nowChannel;
nowChannel = tempChannel;
}
}
客户端
[java] view
plain copy
public class Client {
public static void main(String a[])
{
Command openCommand,closeCommand,changeCommand;
openCommand = new OpenTvCommand();
closeCommand = new CloseTvCommand();
changeCommand = new ChangeChannelCommand();
Controller control = new Controller(openCommand,closeCommand,changeCommand);
control.open(); //打开电视机
control.change(); //换频道
control.change();
control.ChannelUndo();
control.ChannelUndo();
control.ChannelUndo();
control.close(); //关闭电视机
}
}
运行结果。
1. 命令模式的本质就是将命令对象进行封装打包,将发出命令的责任和执行命令的责任进行割开。
2. 命令模式中发送者只需要知道如何发送请求命令,无须关心命令执行具体过程。
3. 在发送者和接收者两者间是通过命令对象进行沟通的。请求命令本身就当做一个对象在两者间进行传递,它封装了接收者和一组动作。
4. 命令模式支持撤销。
5. 命令模式队列请求和日志请求。
相关文章推荐
- 设计模式读书笔记[4]:命令模式(Command)
- 读书笔记之 - javascript 设计模式 - 命令模式
- 设计模式读书笔记之命令模式(Command Pattern)
- 设计模式读书笔记-----命令模式
- 设计模式读书笔记-----命令模式
- 游戏设计模式读书笔记:命令模式
- 设计模式读书笔记之命令模式(Command Pattern)
- 设计模式读书笔记-----命令模式
- 【设计模式】《Head First 设计模式》读书笔记——命令模式
- 读书笔记_java设计模式深入研究 第十章 命令模式 Command
- 23种设计模式4--行为型模式(策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式)
- <读书笔记> Thinking in python (Python 设计模式) 2. Templated Method
- 结合项目实例 回顾传统设计模式(六)命令模式
- 设计模式 - 命令模式(command pattern) 多命令 详解
- 设计模式-命令模式 C++实现
- 【设计模式】从菜鸟到大鸟之命令模式
- 23种设计模式-21-命令模式
- “设计模式”学习之六:职责链与命令模式(行为型)
- Java 设计模式(四)命令模式
- 设计模式(三)结构模式和行为模式(代理模式、享元模式)(观察者模式、命令模式)