hf-ch6-命令模式

0. 序

不知道怎么写序了 遇到了一个之前未遇到的模式。

这一章看到尾确实是太僵硬了,后面会附上我在这章的练习代码!

1. 命令模式

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

命令模式可将“动作请求者”从“动作执行者”对象中解耦。例如:按下按钮后,遥控器就要把电灯打开,那么在此遥控器的实现中就有电灯对象的直接参与造成耦合。–> 如何解耦–> 把请求封装(如打开电灯)成一个特定对象,那么,如果该按钮存储一个命令对象,那么当按钮按下后,就可以命令对象做相应的工作,而不需要知道工作内容是什么。

例子:餐厅中客人点餐,服务员拿了订单,服务员把订单放到窗口,厨师根据订单准备餐点。在这里订单即封装了点餐请求(发出命令),服务员传递订单到窗口(命令传递),这里服务员不需要知道订单上有什么,已经订单给谁。厨师准备餐点(命令实现)。

空对象的使用 指的是不干任何事的对象,可用避免在使用该种类对象时判断if(command!=null) command.execute(); 使用空对象只管调用execute()即可,如果为空的话它什么也不会做(p214)

class OneCommand implements Commend{
    execute(){
        //执行方法语句
        
        ....
    }
}
class NoCommand implements Commend{
    execute(){
   //这里是空的
    }
}

命令模式的更多用途:日程安排(Scheduler) 线程池 工作队列,日志请求等

2. Exercise Code

个人因为这一章的模式之前未接触过,在看书的过程中有似懂非懂的感觉 过完这一章后来梳理一下代码

例子:遥控器的实现

public class Light {
    public   void  on(){
        System.out.println("灯亮了");
    };
    public   void  off(){
        System.out.println("灯灭了");
    };
}
//先不使用命令模式 对一个遥控器该如何实现
/**
 * 假设遥控器有三个槽
 * 每个槽对应开 关 两个按钮 on off
 */
public class 遥控器 {
    private String slot1;//槽1
    private String slot2;//槽1
    private String slot3;//槽1
    public void slot1OnExecute(){
        if (slot1==Light){
            Light.on();
        }else if (slot1==Door){
            Door.on();
        }....
    }
    ...
}
//很显然 这里会有很多if-else 并且如果新增加一个槽的功能,就要加一个if-else 不好维护

因此,采用命令模式,将遥控器的指令封装起来–Command, 该封装带有一个执行方法execute(), 在获取Command对象后执行execute()即可完成命令

/**
 * 封装命令的对象
 */
public interface Command {
    void execute();//执行方法
}

/**
 * 灯亮
 */
public class LightOnCommand  implements Command{
    private  Light light;

    public LightOnCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.on();
    }
}
/**
 * 遥控器
 */
public class RemoteControl {
    Command slot;//一个槽对应一个命令的执行 这里以一个槽为例

    public RemoteControl() {
    }

    public void setSlot(Command slot) {
        //设置每个槽对应的指令
        this.slot = slot;
    }
    public void button1_1Pressed(){
        //槽被按下 执行该槽的方法
        slot.execute();
    }
}


//测试
   public static void main(String[] args) {
        RemoteControl re=new RemoteControl();
        Light light =new Light();
        LightOnCommand lightOnCommand=new LightOnCommand(light);
        re.setSlot(lightOnCommand);
        re.button1_1Pressed();
    }

实现多个槽的遥控器 并带有撤销命令 关于撤销操作,书中的想法很简单,拿出一个变量来记录上一次的命令,若撤销按下则执行该变量记录的命令的undo方法,这里我在想把undo也可撤销,如果要实现这一功能的话就需要记录下undo对应的功能和槽号了

进阶的撤销功能,状态撤销–电风扇的“低,中,高 ”三档

/**
 * 风扇类
 */
public class CeilingFan {
    public static final int HIGH=3;
    public static final int MEDIUM=2;
    public static final int LOW=1;
    public static final int OFF=0;
    String location;
    int speed; //记录当前的速度状态
    public CeilingFan(String location){
        this.location=location;
        speed=OFF;
    }
    public void high(){
        System.out.println("当前执行:"+ location+ " HIGH");
        speed=HIGH;
    }
    public void medium(){
        System.out.println("当前执行:"+ location+ " MEDIUM");
        speed=MEDIUM;
    }
    public void low(){
        System.out.println("当前执行:"+ location+ " LOW");
        speed=LOW;
    }
    public void  off(){
        System.out.println("当前执行:"+ location+ " OFF");
        speed=OFF;
    }

    public int getSpeed() {
        return speed;
    }
}

//高命令 中 低 关闭命令类似
public class CeilingFanHighCommand  implements Command {

    CeilingFan ceilingFan;
    int prevSpeed;//之前的速度 作为撤销命令使用

    public CeilingFanHighCommand(CeilingFan ceilingFan){
        this.ceilingFan=ceilingFan;
    }

    @Override
    public void execute() {
        prevSpeed=ceilingFan.getSpeed();
        ceilingFan.high();
    }

    @Override
    public void undo() {
        if (prevSpeed==CeilingFan.HIGH)
            ceilingFan.high();
        else  if (prevSpeed==CeilingFan.MEDIUM)
            ceilingFan.medium();
        else if (prevSpeed==CeilingFan.LOW)
            ceilingFan.low();
        else if (prevSpeed==CeilingFan.OFF)
            ceilingFan.off();
    }
}

//测试
        CeilingFan ceilingFan_room=new CeilingFan("房间");

        CeilingFanHighCommand ceilingFanHighCommand=new CeilingFanHighCommand(ceilingFan_room);
        CeliFanMediumCommand celiFanMediumCommand=new CeliFanMediumCommand(ceilingFan_room);
        CeliFanLowCommand celiFanLowCommand=new CeliFanLowCommand(ceilingFan_room);
        CeliFanOffCommand celiFanOffCommand=new CeliFanOffCommand(ceilingFan_room);
        

        advancedRemoteControl.setCommand(4,ceilingFanHighCommand,celiFanOffCommand);
        advancedRemoteControl.setCommand(5,celiFanMediumCommand,celiFanOffCommand);
        advancedRemoteControl.setCommand(6,celiFanLowCommand,celiFanOffCommand);
        advancedRemoteControl.hasOnButtonWasPressed(4);//高
        advancedRemoteControl.hasOnButtonWasPressed(5);//中
        advancedRemoteControl.undoButtonWasPressed();
        
当前执行:房间 HIGH
当前执行:房间 MEDIUM
当前执行:房间 HIGH
3. 扩展

一趟走下来发现命令模式其实就是 把一堆的指令封装起来(封装成command) 调用者只需要 对command执行execute()即可,不需要关心该命令如何实现的,不关心该命令的接收者,实现解耦。 即 风扇是一个接收者,打开/调速风扇是指令,将这种指令封装成命令(command) ,在命令封装的过程中就已经确定了该命令的接收者(构造器构造), 再然后在遥控器(调用者)上设置按钮对应的命令,只要按钮被按下就执行execute()方法。

命令模式更多用途:队列请求-- 命令将运算块打包(运算快内包含指令和接收者),然后将他传来传去,直到调用。那么“日程安排(scheduler),线程池,工作队列”等都是这个原理。

在这里插入图片描述

这种情况下,工作队列中的类与进行运算的线程之间是完全解耦的,线程只需要执行队列中的execute()方法即可,而不必关系这个对象是去读取网络数据还是进行数学计算。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值