• 第十七章·命令模式


    一、命令模式概述

    命令模式可以将请求发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。

    定义:
    命令模式:将一个请求封装为一个对象,从而可用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。

    二、命令模式的结构和实现

    2.1 命令模式的结构

    命令模式包含以下4个角色:

    1. Command(抽象命令类):抽象命令类一般是一个抽象类或接口,在其中声明了用于执行请求的execute()等方法,通过这些方法可以调用请求接收者的相关操作。
    2. ConcreteCommand(具体命令类):具体命令类是抽象命令类的子类,实现了在抽象命令类中声明的方法,它对应具体的接收者对象,将接收者对象的动作绑定其中。具体命令类在实现execute()方法时,将调用接收者对象的相关操作(Action)。
    3. Invoker(调用者):调用者即请求发送者,它通过命令对象来执行请求。
    4. Receiver(接收者):接收者执行与请求相关的操作,具体实现对请求的业务处理。

    2.2 命令模式的实现

    //请求调用者

    /**
     * 菜单项,充当请求调用者
     */
    public class MenuItem {
    
        private Command command;
    
        public void setCommand(Command command) {
            this.command = command;
        }
    
        public void click(){
            System.out.println("单击功能键:");
            command.execute();
        }
    
    }
    
    
    /**
     * 主菜单
     */
    public class Menu {
    
        private ArrayList menuItems = new ArrayList<>();
    
        public void addMenuItem(MenuItem menuItem){
            menuItems.add(menuItem);
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    //抽象命令类

    /**
     * 抽象命令类
     */
    public abstract class Command {
    
        public abstract void execute();
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    //具体命令类

    /**
     * 创建命令类,具体命令类
     */
    public class CreateCommand extends Command{
    
        private BoardScreen boardScreen;
    
        public CreateCommand(BoardScreen boardScreen){
            this.boardScreen = boardScreen;
        }
    
        @Override
        public void execute() {
            boardScreen.create();
        }
    }
    
    /**
     * 编辑命令类,具体命令类
     */
    public class EditCommand extends Command{
    
        private BoardScreen boardScreen;
    
        public EditCommand(BoardScreen boardScreen){
            this.boardScreen = boardScreen;
        }
    
        @Override
        public void execute() {
            boardScreen.edit();
        }
    }
    
    /**
     * 打开命令类,具体命令类
     */
    public class OpenCommand extends Command{
    
        private BoardScreen boardScreen;
    
        public OpenCommand(BoardScreen boardScreen){
            this.boardScreen = boardScreen;
        }
    
        @Override
        public void execute() {
            boardScreen.open();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    //请求接收者

    /**
     * 公告板系统界面类
     */
    public class BoardScreen {
    
        public void open(){
            System.out.println("公告板界面打开功能");
        }
    
        public void create(){
            System.out.println("公告板界面创建功能");
        }
    
        public void edit(){
            System.out.println("公告板界面编辑功能");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    //客户端

    public class Client {
    
        public static void main(String[] args) {
    
    
            /**
             * 案例需求描述:
             * 开发一个公告板系统,系统提供一个主菜单Menu,在主菜单中包含了一些菜单项MenuItem,
             * 可以通过Menu类的addMenuItem()方法增加菜单项。
             * 菜单项的主要方法是click(),每一个菜单项包含一个抽象命令类,具体命令类包括openCommand(打开命令),
             * createCommand(新建命令),editCommand(编辑命令)等,命令类有一个execute()方法,
             * 用于调用公告板系统界面类(BoardScreen)的open(),create(),edit()等方法。
             * 请使用命令模式设计该系统。
             */
    
            BoardScreen boardScreen = new BoardScreen();
            Command create, edit, open;
            create = new CreateCommand(boardScreen);
            edit = new EditCommand(boardScreen);
            open = new OpenCommand(boardScreen);
    
            MenuItem menuItem = new MenuItem();
            menuItem.setCommand(create);
            menuItem.click();
    
            menuItem.setCommand(edit);
            menuItem.click();
    
            menuItem.setCommand(open);
            menuItem.click();
    
            Menu menu = new Menu();
            menu.addMenuItem(menuItem);
    
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    三、命令模式的优缺点和适用环境

    3.1 命令模式的优点

    1. 降低了系统的耦合度
    2. 增加新的命令很容易
    3. 可以比较容易地设计一个命令队列或宏命令
    4. 为请求的撤销和恢复操作提供了一种设计和实现方案

    3.2 命令模式的缺点

    1. 使用命令模式可能会导致某些系统有过多的具体命令类

    3.3 命令模式的适用环境

    1. 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互
    2. 系统需要在不同的时间指定请求,将请求排队和执行请求
    3. 系统需要支持命令的撤销操作和恢复操作
    4. 系统需要将一组操作组合在一起形成宏命令(组合命令)

    【参考文献】:
    本文是根据刘伟的《Java设计模式》一书的学习笔记,仅供学习用途,勿做其他用途,请尊重知识产权。

    【本文代码仓库】:https://gitee.com/xiongbomy/java-design-pattern.git

  • 相关阅读:
    开发者生态:共享知识,携手共进,共创技术辉煌
    R语言根据日历周期处理时间序列数据(周、月、年等):使用xts包的apply.yearly函数和mean函数计算时间序列的年平均值(yearly)
    elform-item动态prop
    Java爬虫实战系列——常用的Java网络爬虫库
    javaee spring 声明式事务管理 自定义异常类
    边缘路由器和普通路由器哪个好 边缘路由器跟路由器有什么区别
    c/c++如何实现根据磁盘空间管理自己的日志文件案例
    TwoModalBERT进行角色分类
    源代码审计(白盒测试)
    如何在.NET程序崩溃时自动创建Dump?
  • 原文地址:https://blog.csdn.net/weixin_44143114/article/details/126514446