java 设计模式之命令模式(十三)

人生只能在路上,梦想只能在前方,有心无难事,有诚路就定通,正确的心态能让你的人生更坦然舒心。当然,心态是依靠你自己调整的,只要你愿意,你就可以给自己的一个正确的心态,只要你愿意,你就可以坚持下去。

设计模式学习,近期我会把23种设计模式都写成博客,敬请期待~
—2021/1/16

定义

在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,实现二者之间的松耦合。这就是命令模式(Command Pattern)

百度百科

命令模式分析

  • 命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开。
  • 每一个命令都是一个操作:请求的一方发出请求,要求执行一个操作;接收的一方收到请求,并执行操作。
  • 命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。
  • 命令模式使请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递。
  • 命令模式的关键在于引入了抽象命令接口,且发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联。

简单理解:
要去打仗,将军发布命令 士兵执行命令 将军不会直接和士兵打交道,通过命令来 ‘连接’ 将军和士兵

角色分析

  • ICommand 用来定义命令接口
  • Soldiers士兵 实现ICommand命令接口
  • Admiral将军 聚合了ICommand命令接口,用来发送命令
  • CommandContent命令具体内容

UML类图(1.1):
在这里插入图片描述

项目需求

比如说现在家里有:

  • 电脑
  • 电视
  • 手机
  • 空调

等家电,每个家电都对应一个遥控器,比如这里有4种家电,那么就要对应4种遥控器,非常的麻烦,命令模式就可以将这4种家电把它组合成一个遥控器,可以用一个遥控器来控制这4种家电.像这样

效果图(2.1):

通过遥控器发送命令,然对应的产品实现对应的功能,比如说点击电视打开按钮,就打开电视等操作

代码实现

ICommand(命令接口):

public interface ICommand {
    
    
    //开始
    public void start();

    //撤回
    public void withdraw();
}

CommandContent(命令具体内容):

public class CommandContent {
    
    
    String type;
    
    //传递的是家电 比如说电视 
    public CommandContent(String type) {
    
    
        this.type = type;
    }
    public void on(){
    
    
        Log.i("命令模式",type+"  打开了~ ");
    }
    public void off(){
    
    
        Log.i("命令模式",type+"  关闭了~ ");
    }
}

TvOffCommand,具体实现接口(电视关闭):

public class TvOffCommand implements ICommand{
    
    

    CommandContent dispatchOrders;

    public TvOffCommand(CommandContent dispatchOrders) {
    
    
        this.dispatchOrders = dispatchOrders;
    }
    @Override
    public void start() {
    
    
  		  //如果点击关闭,执行关闭命令
        dispatchOrders.off();
    }
    @Override
    public void withdraw() {
    
    
  		  //点击撤销,执行打开命令 
        dispatchOrders.on();
    }
}

TvOnCommand ,具体实现接口(电视打开):

public class TvOnCommand implements ICommand{
    
    
    CommandContent dispatchOrders;

    public TvOnCommand(CommandContent dispatchOrders) {
    
    
        this.dispatchOrders = dispatchOrders;
    }
    @Override
    public void start() {
    
    
 		//如果点击打开,执行打开命令
        dispatchOrders.on();
    }
    @Override
    public void withdraw() {
    
    
 		  //点击撤销,执行关闭命令
        dispatchOrders.off();
    }
}

NoCommand(空命令,用来第一次初始化,因为第一次既不是打开也不是关闭 ):

public class NoCommand implements ICommand{
    
    
    @Override
    public void start() {
    
    
    }

    @Override
    public void withdraw() {
    
    
    }
}

CallCommand(命令调用者):

public class CallCommand {
    
    

   	//开命令
    ICommand[] tvOnCommand;

    //关命令
    ICommand[] tvOffCommand;

    //记录当前存放的命令 用来撤回
    ICommand currentCommand;

	//默认可存放5条命令
    int number = 5;

	//初始化命令
    public CallCommand() {
    
    
        tvOnCommand = new ICommand[number];
        tvOffCommand = new ICommand[number];

        for (int i = 0; i < number; i++) {
    
    
          //先默认为空的命令
            tvOnCommand[i] = new NoCommand();
            tvOffCommand[i] = new NoCommand();
        }
    }

    /**
     * @param index        当前存放的下标
     * @param OnCommand  开始下标
     * @param OffCommand 结束下标
     */
    public void setTvOnCommand(int index, ICommand OnCommand, ICommand OffCommand) {
    
    
        this.tvOnCommand[index] = OnCommand;
        this.tvOffCommand[index] = OffCommand;
    }

    /**
     * @param index 命令下标
     */
    public void getOnCommand(int index) {
    
    
        this.tvOnCommand[index].start();
        //记录当前命令
        currentCommand =  this.tvOnCommand[index];
    }

    /**
     * @param index 命令下标
     */
    public void getOffCommand(int index) {
    
    
        this.tvOffCommand[index].start();
        //记录当前命令
        currentCommand =  this.tvOffCommand[index];
    }

    /**
     * 撤回
     */
    public void getWithdraw() {
    
    
        currentCommand.withdraw();
    }
}

测试代码(客户端):

		//创建打开电视机命令具体内容
        CommandContent commandContent1 = new CommandContent("电视机");

        //初始化电视机开关命令
        TvOnCommand tvOnCommand = new TvOnCommand(commandContent1);
        TvOffCommand tvOffCommand = new TvOffCommand(commandContent1);

        //创建遥控器
        CallCommand callCommand = new CallCommand();
        //给遥控器初始化电视机开关命令
        callCommand.setTvOnCommand(0,tvOnCommand,tvOffCommand);

        //调用遥控器打开命令
        callCommand.getOnCommand(0);

        //调用遥控器关闭命令
        callCommand.getOffCommand(0);

        //调用遥控器撤回命令
        callCommand.getWithdraw();

Log图(3.1):
在这里插入图片描述
优点:

  • 降低对象之间的耦合度。
  • 新的命令可以很容易地加入到系统中。
  • 准守了开闭原则(对扩展开放,对修改关闭),能够很好的扩展

缺点:

  • 如果是简单的功能会造成代码很多,类很多,不懂命令模式的话会造成阅读苦难.
  • 针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用。

如何进行扩展

假设现在需要添加手机开关的命令:

PhoneOnCommand(手机打开命令):

public class PhoneOnCommand implements ICommand{
    
    

    CommandContent dispatchOrders;

    public PhoneOnCommand(CommandContent dispatchOrders) {
    
    
        this.dispatchOrders = dispatchOrders;
    }
    @Override
    public void start() {
    
    
        dispatchOrders.on();
    }

    @Override
    public void withdraw() {
    
    
        dispatchOrders.off();
    }
}

PhoneOffCommand (手机关闭命令):

public class PhoneOffCommand implements ICommand{
    
    

    CommandContent dispatchOrders;

    public PhoneOffCommand(CommandContent dispatchOrders) {
    
    
        this.dispatchOrders = dispatchOrders;
    }

    @Override
    public void start() {
    
    
        dispatchOrders.off();
    }

    @Override
    public void withdraw() {
    
    
        dispatchOrders.on();
    }
}

测试代码(客户端):

	   //创建命令具体类容
        CommandContent commandContent2 = new CommandContent("手机");
        //创建手机命令
        PhoneOnCommand phoneOnCommand = new PhoneOnCommand(commandContent2);
        PhoneOffCommand phoneOffCommand = new PhoneOffCommand(commandContent2);

        //设置给遥控器命令
        callCommand.setTvOnCommand(1,phoneOnCommand,phoneOffCommand);

        //遥控器打开手机
        callCommand.getOnCommand(1);
        //遥控器关闭手机
        callCommand.getOffCommand(1);
        //遥控器打开手机
        callCommand.getOnCommand(1);
        //遥控器撤销
        callCommand.getWithdraw();

Log图(3.2):
在这里插入图片描述
可以看出,没有改原始代码,只是修改了一下’命令’,依然可以调到对应的方法;

完整代码

去设计模式主页/设计原则

原创不易,您的点赞就是对我最大的支持~

猜你喜欢

转载自blog.csdn.net/weixin_44819566/article/details/112714972
今日推荐