命令模式(Command Pattern)——把方法调用封装起来

前言

​ 在某些场合,比如要对行为进行”记录、撤销/重做、事务”等处理,无法抵御变化的紧耦合是不合适的。在这种情况下,如何将”行为请求者”与”行为实现者”解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。

概述

定义

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

类图

这里写图片描述

  1. Command: 抽象命令类
  2. ConcreteCommand: 具体命令类
  3. Invoker: 调用者
  4. Receiver: 接收者
  5. Client: 客户端
注意
  1. 命令模式将发出请求的对象和执行请求的对象解耦
  2. 在被解耦的两者之间是通过命令对象进行沟通的。命令对象封装了接收者和一个或一组动作
  3. 调用者通过调用命令对象的excute()发出请求,这会使得接收者的动作被调用
  4. 宏命令是命令的一种简单的延伸,允许调用多个命令

         命令模式的本质就在于将命令进行封装,将发出命令的责任和执行命令的责任分开,发送者只需要知道如何发送命令即可,不需要知道命令是如何实现的,甚至命令执行是否成功都不需要理会。同时命令模式使得请求也变成了一个对象,它像其他对象一样可以被存储和传递。

设计模式的实现

场景说明

​ 模拟遥控器控制电视场景。电视剧是请求的接受者,遥控器是请求的发送者,遥控器上有一些按钮,不同的按钮对应着不同的操作。在这里遥控器需要执行三个命令:打开电视机、关闭电视机、换台。

代码实现
package command;

/**
 * <p>ClassName      Command
 * <p>Description    Command命令接口,为所有的命令声明一个接口。所有的命令都应该实现它
 * <p>Author         ChongLou
 * <p>Version
 * <p>Date           2017/8/13 23:17
 */
public interface Command {
    void execute();
}
package command;

/**
 * <p>ClassName      Television
 * <p>Description    电视机类
 * <p>Author         ChongLou
 * <p>Version
 * <p>Date           2017/8/13 23:18
 */
public class Television {
    public void open() {
        System.out.println( "打开电视机......" );
    }

    public void close() {
        System.out.println( "关闭电视机......" );
    }

    public void changeChannel() {

        System.out.println( "切换电视频道......" );
    }
}
package command;

/**
 * <p>ClassName      Controller
 * <p>Description    遥控器类
 * <p>Author         ChongLou
 * <p>Version
 * <p>Date           2017/8/13 23:22
 */
public class Controller {
    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();
    }


}
package command;

/**
 * <p>ClassName      OpenTvCommand
 * <p>Description   遥控器的三个按钮:开电视具体命令类
 * <p>Author         ChongLou
 * <p>Version
 * <p>Date           2017/8/13 23:24
 */
public class OpenTvCommand implements Command {
    private Television tv;

    public OpenTvCommand() {
        tv = new Television();
    }

    public void execute() {
        tv.open();
    }
}
package command;

/**
 * <p>ClassName      ChangeChannelCommand
 * <p>Description    遥控器的三个按钮:换频道具体命令类
 * <p>Author         ChongLou
 * <p>Version
 * <p>Date           2017/8/13 23:26
 */
public class ChangeChannelCommand implements Command {
    private Television tv;

    public ChangeChannelCommand() {
        tv = new Television();
    }

    public void execute() {
        tv.changeChannel();
    }
}
package command;

/**
 * <p>ClassName      CloseTvCommand
 * <p>Description    遥控器三个按钮:关电视具体命令类
 * <p>Author         ChongLou
 * <p>Version
 * <p>Date           2017/8/13 23:26
 */
public class CloseTvCommand implements Command {
    private Television tv;

    public CloseTvCommand() {
        tv = new Television();
    }

    public void execute() {
        tv.close();
    }


}
package command;

/**
 * <p>ClassName      Client
 * <p>Description    客户端
 * <p>Author         ChongLou
 * <p>Version
 * <p>Date           2017/8/13 23:32
 */
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.close();          //关闭电视机
    }

}
运行结果

这里写图片描述

总结

​ 关于前言中所说的撤销操作,这里就不在进行累述了。主要的思路就是在Invoker中记录之前的一个或者多个状态。在必要时恢复。

​ 命令模式的更多用途:队列请求(这里是有些模糊?)、日志请求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值