设计模式-----命令模式

来源:互联网 发布:js中文姓名正则表达式 编辑:程序博客网 时间:2024/06/03 18:11

设计模式—–命令模式

个人博客,想要搭建个人博客的可以进来看看: http://www.ioqian.top/


命令模式 , 将请求封装成对象,以便使用不同的请求,队列或日志来参数化其他对象,命令模式也支持可撤销的操作

设计模式系列源码: https://github.com/liloqian/DesiginModeDemo

背景
现在有一个遥控器,上面有1个按钮,我们要根据不同的请求来控制不同的电器,比如说可以控制风扇,点灯等,这里我们就可以引入命令模式

在面向对象的程序设计中,一个对象调用另一个对象,一般情况下的调用过程是:创建目标对象实例;设置调用参数;调用目标对象的方法。
但在有些情况下有必要使用一个专门的类对这种调用过程加以封装,我们把这种专门的类称作command类。

1.下面先大概看一下UML
此处输入图片的描述

  • Command ,是所有命令的一个接口,调用Command中的execute()方法就可以让接受者进行相关的动作
  • Receiver , 动作的最终执行者 ,比如我们背景中的风扇 , 电灯,打开风扇,打开电灯等动作最终只可能由电灯风扇自身实现
  • CreateCommand ,持有Receiver的引用,继承了Command接口,在Command接口的execute()方法中直接调用Receiver的具体动作
  • Invoker , 调用者,持有一个命令接口,当客户调用时直接调用命令接口的execute()方法

2.下面来看具体的代码
Receiver,这里实现了2个命令接收者,分别是风扇和电灯

/**Receiver  具体的命令接收者,接受者指导如何进行必要的工作,也是真正执行命令的方法*/public class Light {    //实现了这个方法都可以成为命令接收者,这个方法是真正执行命令的方法,对应上图中的action()方法    public void on(){        System.out.println(this.toString()+":  turn on the light");    }    @Override    public String toString() {        return "I-am-light";    }}/**另外一个接受者*/public class Fan {    public void on(){        System.out.println(this.toString()+":  turn on the fan");    }    @Override    public String toString() {        return "I-am-fan";    }}

Command接口

/**命令接口,所以的遥控器控制的电器命令都要实现这个接口*/public interface Command {    public void execute();}

CreateCommand,实现了Command接口的具体命令,持有接受者Receiver的引用

/**CreateCommand*/public class LightCommand implements Command {    //持有一份接受者Receiver中Light的引用    Light light ;    public LightCommand(Light light) {        this.light = light;    }    @Override    public void execute() {        light.on();    }}/**和上面的一样*/public class FanCommand implements Command {    Fan fan;    public FanCommand(Fan fan) {        this.fan = fan;    }    @Override    public void execute() {        fan.on();    }}

Invoker

/**Invoker 持有一个命令对象,当点击按钮时就执行命令对象的方法*/public class SimpleRemoteControl {    //命令对象    Command command;    //点击按钮后调用此方法去调用命令对象实现的方法    public void buttonPressed(){        command.execute();    }    public void setCommand(Command command) {        this.command = command;    }}

Client ,直接在Main测试中进行

public class Main {    public static void main(String[] args) {        //实例化一个命令调用者        SimpleRemoteControl remote = new SimpleRemoteControl();        //电灯命令        LightCommand lightOn = new LightCommand(new Light());        //设置电灯命令,点击按钮去执明LightCommand的方法        remote.setCommand(lightOn);        remote.buttonPressed();        //下面的和上面的一样        FanCommand fanOn = new FanCommand(new Fan());        remote.setCommand(fanOn);        remote.buttonPressed();    }}//结果 , 我们通过传入不同的命令参数可以执行不同的请求I-am-light:  turn on the lightI-am-fan:  turn on the fanProcess finished with exit code 0

上面的模型中也可以不必一定要有Receiver,可以把具体的动作放在ConcreteCommand中

3.命令模式的用途,队列请求

新建一个专门处理请求对象的线程,从队列获取请求对象(就是请求封装的对象),进行处理;在其他线程中把请求封装成对象加入这个队列

此处输入图片的描述

4.命令模式的要点

  • 命令模式将要发出请求的对象和执行请求的对象解耦,执行请求的对象不关心请求的具体内容,只要把具体的请求封装成请求的对象就可以了
  • 被解耦的两者之间是通过命令对象进行沟通的,命令对象封装了接收者和一个或一组动作
  • 调用者通过调用命令对象的execute()方法使得接受者的动作被执行
  • 命令可以被撤销,做法是实现一个undo()方法来回到execute()之前的状态,undo()和execute()的具体实现一样
  • 实际中,使用聪明命令对象,而不是把工作给了接受者,就是前面说的,不必一定要有Receiver,可以把具体的动作放在ConcreteCommand中
原创粉丝点击