白话设计模式之命令模式

2022-07-26 16:59:52 浏览数 (1)

命令模式介绍

命令模式将需要执行的命令进行封装,请求方发送请求,接收方收到请求后执行请求,命令模式使请求者和接收者不用关心怎么调用和执行,只需要执行即可,屏蔽了实现,使请求方和接收方彻底的解耦,现实中也随处可见命令模式的使用,比如我们使用的电视机,我们只需要按下遥控器的按钮,便可以实现开关机,换台,调声音等,我们使用的空调,电磁炉,电饭煲也是如此,并不需要我们去将这根线和那根线结合,而是按相应的按钮即可。

命令模式中已经带了命令二字,现实生活中,老板命令我去加班,我就加班,老板命令我倒茶,我就倒茶,这有点把自己说成工具人的意思,但是确实是这个样子的,不过话又说回来了,不是工具人是什么啊

,老板的吩咐就是一句指令,我按照要求去做就得了,我们在操作Linux系统的时候,也是发出一条一条的指令,但是我们并不需要去关心它怎么执行,下面我们用一个案例来实现命令模式。

实现命令模式

我们现在来实现一个电饭煲的基本功能,开,关,煮饭,当然还有其它的很多功能,比如煮粥这些,都一样,这里我们以这三个为例。

定义一个命令的接口IRiceCookerCmd,后续所有的具体命令都要实现它

代码语言:javascript复制
//电饭煲命令
public interface IRiceCookerCmd {
    void execute();
}

编写打开电饭煲命令接口OpenRiceCookerCmd

代码语言:javascript复制
//打开电饭煲命令
public class OpenRiceCookerCmd implements IRiceCookerCmd {
    private final RiceCookerReceiver receiver = new RiceCookerReceiver();
    @Override
    public void execute() {
        receiver.open();
    }
}

关闭电饭煲命令接口CloseRiceCookerCmd

代码语言:javascript复制
//关闭电饭煲命令
public class CloseRiceCookerCmd implements IRiceCookerCmd {
    private final RiceCookerReceiver receiver = new RiceCookerReceiver();
    @Override
    public void execute() {
        receiver.close();
    }
}

煮饭命令CookRiceCmd

代码语言:javascript复制
//煮饭命令
public class CookRiceCmd implements IRiceCookerCmd {
    private final RiceCookerReceiver receiver = new RiceCookerReceiver();
    @Override
    public void execute() {
        receiver.cookRice();
    }
}

编写接收者RiceCookerReceiver ,接收者是真正执行命令的对象

代码语言:javascript复制
public class RiceCookerReceiver {
    private static boolean flag = false;
    public void open(){
        flag = true;
        System.out.println("open it");
    }
    public void close(){
        flag = false;
        System.out.println("close it");
    }
    public void cookRice(){
        if (flag)
            System.out.println("start cooking rice");
        else
            System.out.println("please open the rice cooker , than cook rice");
    }
}

编写调用者RiceCookerInvoker,调用者是真正发出命令和执行命令的对象,此处用一个List来存放命令,因为可能多个命令一起执行。

代码语言:javascript复制
public class RiceCookerInvoker {
    private final List<IRiceCookerCmd> cmds = new ArrayList<>();
    public void addCmd(IRiceCookerCmd riceCookerCmd){
        cmds.add(riceCookerCmd);
    }
    public void executeCmd(){
        cmds.forEach(IRiceCookerCmd::execute);
        cmds.clear();
    }
}

客户端调用,我们只需要创建出对应的操作命令(电饭煲的按钮),然后便可完成相应的操作,如下我们按电饭煲开机按钮,然后按电饭煲煮饭按钮。

代码语言:javascript复制
public class Client {
    public static void main(String[] args) {
        IRiceCookerCmd openRiceCookerCmd = new OpenRiceCookerCmd();
        IRiceCookerCmd cookerCmd = new CookRiceCmd();
        RiceCookerInvoker riceCookerInvoker = new RiceCookerInvoker();
        riceCookerInvoker.addCmd(openRiceCookerCmd);
        riceCookerInvoker.addCmd(cookerCmd);
        riceCookerInvoker.executeCmd();
    }
}

下面我们关闭电饭煲

代码语言:javascript复制
public class Client {
    public static void main(String[] args) {
        IRiceCookerCmd closeRiceCookerCmd = new CloseRiceCookerCmd();
        RiceCookerInvoker riceCookerInvoker = new RiceCookerInvoker();
        riceCookerInvoker.addCmd(closeRiceCookerCmd);
        riceCookerInvoker.executeCmd();
    }
}

经过上面的一系列操作,我们就能吃上香喷喷的米饭了,我们发现,上面的代码中涉及很多部分,命令接口IRiceCookerCmd ,它是用来声明执行的方法,命令接口实现对象,如CookRiceCmd,CloseRiceCookerCmd ,但是具体命令并不是由它来做的,它内部会维护一个接收者,并且调用接收者来做实际的操作,接收者Receiver,它是真正执行命令的对象,调用者Invoker,它接收客户端的命令,并发起请求,客户端Client,它是命令的发起者,比如我按下电饭煲的开关按钮,我就是Client。

我们思考一下,其实命令接口实现对象位于Invoker和Receiver中间,它不做具体的实现,只是起到一个中间衔接的作用,这样就解耦了Invoker和Receiver。

命令模式的应用场景

我们在软件开发过程中,如果觉得某一个功能的每个请求都是一个命令,那么就可以考虑使用命令模式。

命令模式的优点

1.系统的扩展性好,如果有新的命令加入,则编写对应的命令实现类即可。

2.通过引入命令接口,降低系统的耦合度。

命令模式的缺点

如果具体的命令实现类过多,会增加系统的复杂度。

今天的分享就到这里,感谢你的观看,我们下期见。

0 人点赞