设计模式学习第十四节 命令模式

概述

    基本介绍
    1、命令模式(Command Pattern):“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,实现二者之间的松耦合。这就是命令模式,也叫做Action/Transaction
    2、在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需要在程序运行时指定具体的请求接收者即可,此时可以使用命令模式来设计。
    3、命令模式是的请求发送者与请求接收者消除彼此之间的耦合,让对象之间调用关系更加灵活,实现解耦。
    4、在命令模式中,会将一个请求封装为一个对象,以便使用不同参数来表示不同的请求,命令模式支持可撤销的操作。
    5、角色有 Invoker 调用者、Receiver被调用者,MyCommand 具体命令实现了 Command接口,持有接收对象。
    类图简介
在这里插入图片描述
    角色说明
    Invoker 调用者角色
    Command:是命令角色,需要执行的命令都在这里,可以是接口或者抽象类。
    Receiver:接收者角色,如何实施和执行一个相关的操作。
    ConcreteCommand:将一个接收者对象与一个动作绑定,调用接收者相应的操作,实现execute或者 undo操作。

举例实现

    实现遥控器控制电视和电灯开关的功能,类图解析
在这里插入图片描述
    代码实现

package com.example.pattern.command;

import lombok.Getter;
import lombok.Setter;
import org.springframework.util.CollectionUtils;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Map;

/**
 * 命令模式
 */
public interface Command { // 创建命令接口

    // 执行操作
    void execute();

    // 撤销操作
    void undo();

}


// 没有任何命令 就是空执行 用户初始化每个按钮,当调用空命令时,对象不进行任何操作
// 省去对象的空判断
class NoCommand implements Command {
    @Override
    public void execute() {

    }

    @Override
    public void undo() {

    }
}

@Setter
@Getter
class LightOnCommand implements Command { // 打开电灯命令

    // 聚合LightReceiver 执行命令的具体类
    private LightReceiver light;

    public LightOnCommand(LightReceiver lightReceiver) {
        this.light = lightReceiver;
    }

    @Override
    public void execute() {
        // 调用接收者的具体方法
        light.on();
    }

    @Override
    public void undo() {
        // 调用接收者的具体方法
        light.off();
    }
}

@Setter
@Getter
class LightOffCommand implements Command { // 关闭电灯命令

    // 聚合LightReceiver 执行命令的具体类
    private LightReceiver light;

    public LightOffCommand(LightReceiver lightReceiver) {
        this.light = lightReceiver;
    }

    @Override
    public void execute() {
        // 调用接收者的具体方法
        light.off();
    }

    @Override
    public void undo() {
        // 调用接收者的具体方法
        light.on();
    }
}

class LightReceiver {

    public void on() {
        System.out.println("   电灯打开了   ");
    }

    public void off() {
        System.out.println("   电灯关闭了    ");
    }

}

@Getter
@Setter
class RemoteControl { // 遥控器类
    private Map<String, Command> map;

    // 开按钮的命令
    private Command[] onCommands;

    // 关按钮的命令
    private Command[] offCommands;

    // 执行撤销的命令
    private LinkedList<Command> undoCommandList = new LinkedList<>();

    // 构造器 完成初始化

    public RemoteControl() {
        onCommands = new Command[2];
        offCommands = new Command[2];
        Arrays.stream(onCommands).forEach(item -> item = new NoCommand());
        Arrays.stream(offCommands).forEach(item -> item = new NoCommand());
    }

    // 给按钮设置命令
    public void setCommand(int no, Command onCommand, Command offCommand) {
        onCommands[no] = onCommand;
        offCommands[no] = offCommand;
    }

    // 执行开启命令
    public void onButtonPushed(int no) {
        onCommands[no].execute();
        undoCommandList.addLast(onCommands[no]);
    }

    // 执行关闭命令
    public void offButtonPushed(int no) {
        offCommands[no].execute();
        undoCommandList.addLast(offCommands[no]);
    }

    // 撤销命令
    public void undoButtonPushed() {
        if (!CollectionUtils.isEmpty(undoCommandList)) {
            Command last = undoCommandList.getLast();
            last.undo();
            undoCommandList.remove(last);
        }
    }

}

class Client {
    public static void main(String[] args) {
        // 使用命令设计模式 通过遥控器对电灯的操作
        // 创建电灯的对象
        LightReceiver lightReceiver = new LightReceiver();
        // 创建电灯打开的命令
        LightOnCommand lightOnCommand = new LightOnCommand(lightReceiver);
        // 创建电灯关闭的命令
        LightOffCommand lightOffCommand = new LightOffCommand(lightReceiver);
        // 创建一个遥控器
        RemoteControl remoteControl = new RemoteControl();
        // 设置遥控器的命令
        remoteControl.setCommand(0, lightOnCommand, lightOffCommand);
        System.out.println("-----------按下电灯开的按钮-------------");
        remoteControl.onButtonPushed(0);
        System.out.println("-----------按下电灯关闭的按钮-------------");
        remoteControl.offButtonPushed(0);
        // 创建电视的对象
        TVReceiver tvReceiver = new TVReceiver();
        // 创建电视打开的命令
        TVOnCommand tvOnCommand = new TVOnCommand(tvReceiver);
        // 创建电视关闭的命令
        TVOffCommand tvOffCommand = new TVOffCommand(tvReceiver);
        // 设置遥控器的命令
        remoteControl.setCommand(1, tvOnCommand, tvOffCommand);
        System.out.println("-----------按下电视开的按钮-------------");
        remoteControl.onButtonPushed(1);
        System.out.println("-----------按下电视关闭的按钮-------------");
        remoteControl.offButtonPushed(1);
        System.out.println("-----------按下撤销的按钮-------------");
        remoteControl.undoButtonPushed();
        remoteControl.undoButtonPushed();
        remoteControl.undoButtonPushed();
        remoteControl.undoButtonPushed();
        remoteControl.undoButtonPushed();
        remoteControl.undoButtonPushed();
    }
}

// 命令模式扩展比较简单 下面是新增一个 电视的命令
class TVReceiver {
    public void on() {
        System.out.println("   电视打开了   ");
    }

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

@Getter
@Setter
class TVOnCommand implements Command {
    // 聚合LightReceiver 执行命令的具体类
    private TVReceiver tv;

    public TVOnCommand(TVReceiver tvReceiver) {
        this.tv = tvReceiver;
    }

    @Override
    public void execute() {
        // 调用接收者的具体方法
        tv.on();
    }

    @Override
    public void undo() {
        // 调用接收者的具体方法
        tv.off();
    }
}

@Getter
@Setter
class TVOffCommand implements Command {
    // 聚合LightReceiver 执行命令的具体类
    private TVReceiver tv;

    public TVOffCommand(TVReceiver tvReceiver) {
        this.tv = tvReceiver;
    }

    @Override
    public void execute() {
        // 调用接收者的具体方法
        tv.off();
    }

    @Override
    public void undo() {
        // 调用接收者的具体方法
        tv.on();
    }
    
}

命令模式优缺点分析

    1、将发起请求的对象于执行请求的对象解耦。发起请求的对象是调用者,调用者只要调用命令对象的execute()方法就可以让接收者工作,而不必知道具体的接收者对象是谁,是如何实现的,命令对象会负责让接收者执行请求的动作,也就是说“请求发起者”和“请求执行者”之间的解耦是通过命令对象实现的,命令对象起到了纽带桥梁的作用。
    2、设计一个命令队列,只要把命令对象放到队列,就可以多线程执行命令。
    3、容易实现对请求的撤销和重做。
    4、命令模式的缺点:可能导致某些系统有过多的具体命令类,增加了系统的复杂度,这点在使用的时候需要注意。
    5、空命令也是一种设计模式,它为我们省去了空判断操作,在上面的实例中,如果没有空命令,每一个按键功能都需要空判断,代码冗余度加大。
    6、命令模式的经典应用场景:界面的一个按钮就是一条命令、模拟CMD(DOS)命令、出发-反馈机制。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值