命令模式

命令模式概述

  1. 什么是命令模式: 是一种行为型设计模式,将命令与具体实现进行解耦,将命令封装为对象数据进行传递,命令只关注与"执行",“撤销执行”,而命令具体执行的是什么,有下一层的接收者根据命令对象的不同来决定
  2. 命令模式的优点: 将请求与具体行为解耦,提高扩展性方便添加新的命令,可以比较容易的设置组合命令,记录命令,通过记录命令实现命令撤销

分析命令模式中的角色

  • 接收者Receiver: 具体产品功能类,执行功能动作

  • 命令Command: 为所有命令抽象的的父接口,提供执行命令的execute()与撤销执行命令的undo()方法

  • 具体命令一 ConcreteCommand1: 空命令,根据需求,不是必须创建的,实现命令接口,重写空的执行与撤销执行方法,在初始化时,并未真实对命令进行设置,此时执行命令调用的是空命令中的空方法

  • 思考问题: 命令与功能进行解耦后,命令只关注与"执行",“撤销执行”,那命令执行的是什么? 命令执行的功能功能是什么?就好像上面,实现了命令接口的空命令,命令执行,执行的是空方法,也就是什么都不执行根据产品与功能,实现命令接口创建"产品功能命令执行"子类,重写命令执行抽象方法"产品功能命令"子类中持有产品对象,命令执行方法中通过产品对象调用功能方法,由此处可以看出,当一个系统中功能命令过多时,使用命令模式,则会造成命令类过于庞大

  • 具体命令二 Concrete1Command1: 可能有多个,根据产品与功能两个维度创建的,我理解为命令与指定功能动作的绑定,该角色持有接收者,实现命令接口,重写执行命令与撤销命令方法,当执行命令是通过持有的接受者对象调用指定功能方法

  • 请求者Invoker: 我理解为用来存放不同命令的容器,同时也是客户端触发命令执行,客户端与命令的解耦层,定义了用来存放不同类型命令的容器,定义了初始化命令的方法,设置命令的方法,与执行命令的方法

命令模式流程图(不是UML)

在这里插入图片描述

命令模式代码示例

案例与分析

  • 案例: 通过命令模式设计遥控器开灯关灯
  • 产品功能: “开灯”,“关灯”
  • 命令: “执行”,“撤销执行”
  1. 创建产品功能类,对应角色Receiver
//创建"灯",灯可以实现"开灯","关灯"两个功能
class LightReceiver{

    public void on() {
        System.out.println("打开电灯");
    }
    public void off() {
        System.out.println("关闭电灯");
    }
}
  1. 创建命令父接口,对应角色Command
//创建执行命令接口:抽象出接口的原因: 为了以后更好的扩展,
//现在的示例是只针对"灯"发送命令执行,假设后续需求增加
//要对电视,洗衣机...也发送命令怎么办?
//命令与功能进行解耦后,命令只关注执行与停止撤销执行,所以定
//义两个抽象方法,根据需求来的,例如在某些场景下,解耦后只有
//"执行"一种命令,"执行打开","执行关闭","执行xxx"都是执行
abstract class Command{
    //执行动作
    abstract void execute();
    //撤销动作
    abstract void undo();
}

  1. 创建具体命令实现子类一,空命令,对应角色ConcreteCommand1
//实现命令接口创建执行命令的实现子类一"空命令"类
//创建空命令的原因是在初始存放执行命令的容器
//时,并没有实际存放命令,专门用初始化命令的
//假设需求中在初始化命令容器时可以直接指定存放的
//命令类型,则可以不使用该类
//执行时命令对象调用执行方法,则执行此处的空方法
class NoCommand extends Command{

    @Override
    public void execute() {

    }

    @Override
    public void undo() {

    }
}
  1. 根据产品功能创建具体命令实现子类,命令与执行的动作进行绑定,对应角色Concrete1Command1:“灯"有两个功能"开灯”,“关灯”,执行灯的命令就是"执行开灯",“执行关灯”

开灯命令类

//根据产品与功能创建执行命令实现子类二: "开灯命令类",该类中重点关注"开灯"功能
class LightOnCommand extends Command{
    //持有灯对象
    public LightReceiver light;
    //通过构造器赋值
    public LightOnCommand(LightReceiver light) {
        this.light = light;
    }
    //重写执行命令接口: 该命令为"开灯"命令
    //当执行该命令时,通过持有的产品对象"灯"light
    //调用开灯方法 on()
    @Override
    public void execute() {
        light.on();
    }

    //重写撤销执行方法,通过light调用关灯方法
    @Override
    public void undo() {
        light.off();
    }
}

关灯命令类

//根据产品与功能创建"执行命令"实现子类三: "关灯命令"类,该类中重点关注"关灯"功能
class LightOffCommand extends Command{
    //持有产品对象
    public LightReceiver light;
    //通过构造器赋值
    public LightOffCommand(LightReceiver light) {
        this.light = light;
    }

    //重写命令执行方法,方法中通过产品调用功能方法
    @Override
    public void execute() {
        light.off();
    }
    //重写撤销命令方法,方法中通过产品调用执行前的方法
    @Override
    public void undo() {
        light.on();
    }
}
  1. 创建持有命令,接收客户端请求,通过持有命令,执行功能的遥控器 对应角色Invoker
//遥控器,我理解为用来存放不同命令的容器,
//同时也是客户端触发命令执行,客户端与命令的解耦层
//定义了用来存放不同类型命令的容器,定义了初始化命令的方法
//设置命令的方法,与执行命令的方法
class RemoteController{
    //存放命令的容器(此处使用数组,分别定义3个,用来存放不同类型的命令)
    //存放"开"命令容器
    public Command[] onCommands;
    //存放"关"命令容器
    public Command[] offCommands;
    //记录上次执行的命令
    public Command undoCommand;

    //构造器完成命令初始化,注意由于在最初初始化时,并不知道
    //该"开"或"关"的命令是针对哪个设备的,所以使用NoCommand
    //假设遥控器有5个按钮,所以初始化了5个命令
    public RemoteController() {
        onCommands = new Command[5];
        offCommands = new Command[5];
        for(int i = 0; i<5; i++) {
            onCommands[i] = new NoCommand();
            offCommands[i] = new NoCommand();
        }
    }

    //给指定按钮设置需要的命令(设置命令)
    public void setCommand(int num, Command onCommand, Command offCommand) {
        onCommands[num] = onCommand;
        offCommands[num] = offCommand;
    }

    //按下开的按钮(执行命令)
    public void buttonOnCommand(int num) {
        onCommands[num].execute();
        //记录此次的操作,供撤销使用
        undoCommand = onCommands[num];
    }

    //按下关的按钮(执行命令)
    public void buttonOffCommand(int num) {
        offCommands[num].execute();
        //记录此次的操作,供撤销使用
        undoCommand = offCommands[num];
    }

    //按下撤销(执行命令)
    public void buttonUndo() {
        undoCommand.undo();
    }
}
  1. 客户端调用
	public static void main(String[]args) {
        //创建点灯对象
        LightReceiver lightReceiver = new LightReceiver();

        //创建电灯开关命令
        LightOnCommand lightOn = new LightOnCommand(lightReceiver);
        LightOffCommand lightOff = new LightOffCommand(lightReceiver);

        //创建遥控器
        RemoteController remote = new RemoteController();

        //给遥控器设置命令
        remote.setCommand(0, lightOn, lightOff);

        //按下灯的开按钮
        remote.buttonOnCommand(0);
        //按下灯的撤销按钮
        remote.buttonUndo();

        //按下灯的关按钮
        remote.buttonOffCommand(0);
        //按下灯的撤销按钮
        remote.buttonUndo();
    }

根据代码分析

我理解的命令模式是: 将命令与实际功能进行剥离,创建命令类与功能类,命令类中提供命令执行的方法,然后新增命令与功能进行绑定的类,例如开灯命令,关灯命令,命令功能绑定类继承命令类,并持有功能类对象,重写执行命令的方法,在方法中通过持有的功能类对象调用功能方法,进而实现命令执行功能执行

发布了31 篇原创文章 · 获赞 0 · 访问量 371
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 1024 设计师: 上身试试

分享到微信朋友圈

×

扫一扫,手机浏览