写点什么

CommandPattern- 命令模式

作者:梁歪歪 ♚
  • 2022 年 6 月 02 日
  • 本文字数:2448 字

    阅读完需:约 8 分钟

CommandPattern-命令模式

命令模式

命令模式(Command Pattern):是对命令的封装,每一个命令都是一个操作。首先请求的一方发出请求要求执行一个操作,然后接收的一方收到请求,并执行操作。


命令模式属于行为型模式,解耦了请求方和接收方,请求方只需要发送命令而不需要关心命令是如何被接收的、不关心命令怎么操作、也不关心命令是否被执行等。


命令模式典型的场景就是我们使用的DOS命令Shell命令,我们通过控制台发送命令,然后控制台将命令交给真正的执行者,而控制台在这里的作用就是充当了一个中间联系人。


示例:我们就通过发送 Shell 命令来举例说明...


  • Linux 操作系统类LinuxSystem.java


package cn.liangyy.command;
/** * Linux操作系统类 */public class LinuxSystem { public void cd(){ System.out.println("已经切换到主目录!"); }
public void ls(){ System.out.println("已经列举出当前目录下所有文件!"); }
public void restart(){ System.out.println("开启重启系统!"); }}
复制代码


  • 命令接口ICommand.java


package cn.liangyy.command;
/** * 命令接口 */public interface ICommand { /** * 执行命令 */ void execute();}
复制代码


  • cd 命令类CdCommand.java


package cn.liangyy.command;
/** * cd 命令类 */public class CdCommand implements ICommand { //持有真正的命令执行者 Linux 操作系统 private LinuxSystem linuxSystem; /** * 执行命令 */ @Override public void execute() { //调用真正的执行者来执行命令 linuxSystem.cd(); }}
复制代码


  • ls 命令类LsCommand.java


package cn.liangyy.command;
/** * ls命令类 */public class LsCommand implements ICommand { private LinuxSystem linuxSystem; /** * 执行命令 */ @Override public void execute() { linuxSystem.ls(); }}
复制代码


  • restart 命令类RestartCommand.java


package cn.liangyy.command;
/** * restart命令类 */public class RestartCommand implements ICommand { private LinuxSystem linuxSystem; /** * 执行命令 */ @Override public void execute() { linuxSystem.restart(); }}
复制代码


  • 命令的请求者类XshellInvoker.java


package cn.liangyy.command;
import java.util.ArrayList;import java.util.List;
/** * 命令的请求在类 */public class XshellInvoker { //封装了命令的list集合 private List<ICommand> commandList = new ArrayList<>();
public XshellInvoker(List<ICommand> commandList) { this.commandList = commandList; }
/** * 执行指定命令 * @param command */ public void execute(ICommand command){ command.execute(); }
/** * 执行命令宏,即执行特定的几个命令组合 */ public void executeCdAndLs(){ for (ICommand command : commandList){ //只执行待定的命令宏 if (command instanceof LsCommand || command instanceof CdCommand){ command.execute(); } } }
/** * 执行全部命令 */ public void executeAll(){ //通过循环的方式执行每一条命令 for (ICommand command : commandList){ command.execute(); } }}
复制代码


  • 测试TestCommand.java


package cn.liangyy.command;
import java.util.ArrayList;import java.util.List;
/** * 命令模式-测试 */public class TestCommand { public static void main(String[] args) { //创建命令真正的执行者 LinuxSystem linuxSystem = new LinuxSystem();
//创建三个命令 List<ICommand> commandList = new ArrayList<>(); commandList.add(new CdCommand(linuxSystem)); commandList.add(new LsCommand(linuxSystem)); commandList.add(new RestartCommand(linuxSystem));
//初始化命令请求者 XshellInvoker xshellInvoker = new XshellInvoker(commandList); //执行指定命令 xshellInvoker.execute(new LsCommand(linuxSystem)); System.out.println("========================"); //执行特定命令宏 xshellInvoker.executeCdAndLs(); System.out.println("========================"); //执行全部命令 xshellInvoker.executeAll(); }}
复制代码


上面就是一个命令模式的标准写法。我们可以看到,因为控制器已经与命令执行者实现了解耦,后面如果想要继续扩展新的命令,那么再增加一个命令类就行了。


桥接模式、中介者模式、命令模式这三种模式我特意放在一起讲解,因为这三种模式有一个共性,都是通过一个中间者来实现解耦,我们会很容易产生误解:


  • 桥接模式:注重的是两个维度之间的解耦,一个抽象维度,一个实现维度。

  • 中介者模式:注重的是同事对象之间的解耦,各个同事对象是属于同一种类型的平级对象。

  • 命令模式:其侧重的是发送方和请求方,也就是必须要有发送方和请求方才能构成一个完整的整体。像桥接如果缺少某一方只是缺少了功能,但是依然可以正常使用;而中介者就更不用说了,同事多一个少一个在技术上完全不影响。


命令模式适用场景


  • 现实语义中存在具备“命令”的操作,如:dos 命令,shell 命令。

  • 请求调用者和请求接收者需要解耦,使得调用者和接收者不直接互相调用。


命令模式优点


  • 通过引入中间件(抽象接口)解耦了请求与实现。

  • 扩展方便,增加新命令直接增加一个对象即可。

  • 可以支持命令的组合操作,比较灵活方便。


命令模式缺点


  • 如果命令过多的时候,会多出非常庞大的对象。

  • 命令的接受者如果需要新增命令或者命令组合则需要修改源码,不符合开闭原则。

发布于: 刚刚阅读数: 4
用户头像

梁歪歪 ♚

关注

还未添加个人签名 2021.07.22 加入

还未添加个人简介

评论

发布
暂无评论
CommandPattern-命令模式_设计模式_梁歪歪 ♚_InfoQ写作社区