《设计模式》命令模式

news2024/11/20 20:19:19

《设计模式》设计模式的基本原则
《设计模式》单例模式
《设计模式》工厂模式
《设计模式》原型模式
《设计模式》建造者模式
《设计模式》适配器模式
《设计模式》桥接模式
《设计模式》装饰者模式
《设计模式》组合模式
《设计模式》外观模式
《设计模式》享元模式
《设计模式》代理模式
《设计模式》模板方法模式
《设计模式》命令模式

《设计模式》命令模式

定义

  • 命令模式就是将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分离,消除请求发送者和请求接收者之间的耦合,让对象之间调用的关系更加灵活,同时命令模式也支持可撤销的操作。

命令模式的优缺点

  • 优点:降低系统的耦合度,将调用对象和实现对象解耦;扩展灵活,增加或删除命令不会影响其他类。并且容易设计一个命令队列,使用多线程去执行队列中的命令。
  • 缺点:会导致系统有过多的具体命令类,增加系统的复杂度。

命令模式的使用场景

  • 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
  • 系统需要在不同的时间指定请求、将请求排队和执行请求。
  • 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。

命令模式的角色组成

  • 抽象命令(Command):定义命令的接口,声明执行的方法。
  • 具体命令(Concrete Command):具体的命令实现命令接口,通常会持有接收者,并调
    用接收者的功能来完成命令要执行的操作。
  • 实现者/接收者(Receiver):接收者是真正执行命令的对象,任何类都可能成为一个接收
    者,只要它能够实现命令要求实现的相应功能。
  • 调用者/请求者(Invoker):调用命令对象执行请求,通常会持有命令对象,可以持有很
    多的命令对象。

命令模式的原理类图如下所示

在这里插入图片描述

案例背景

生活中有这样一个场景:我们去饭店吃饭的时候,服务员先把菜单拿给我们,我们在选好菜之后,再将菜单交给服务员,然后由服务员将菜单告知后厨备菜。其实,在这样的场景中,也可以看成是命令模式的应用。服务员作为命令的调用者 Invoker,负责命令厨师备菜,厨师此时就是命令的接收者 Receiver,具体的命令就是顾客的订单 OrderCommand.

关系类图如下所示

在这里插入图片描述

Command 接口:

public interface Command {
    void execute();

    void undo();
}

OrderCommand 类:

public class OrderCommand implements Command{
    private Chef receiver;
    private Order order;

    public OrderCommand(Chef receiver, Order order) {
        this.receiver = receiver;
        this.order = order;
    }

    @Override
    public void execute() {
        System.out.println("-------------------------");
        System.out.println(order.getDiningTable() + "桌的订单:");

        Set<String> keys = order.getFoodDic().keySet();
        for (String key : keys) {
            receiver.makeFood(order.getFoodDic().get(key), key);
        }
        try {
            // 停顿一下模拟做饭的过程
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
            Thread.currentThread().interrupt();
        }
        System.out.println(order.getDiningTable() + "桌的饭弄好了");
    }

    @Override
    public void undo() {
        System.out.println("--------------------------");
        StringBuilder cancel = new StringBuilder();
        cancel.append(order.getDiningTable()).append("桌的订单:");
        Set<String> keys = order.getFoodDic().keySet();
        for (String key : keys) {
            cancel.append(order.getFoodDic().get(key)).append("份").append(key);
        }
        receiver.cancelMakeFood(cancel.toString());
    }
}

Order 类:

public class Order {

    private int diningTable;

    private Map<String, Integer> foodDic = new HashMap<>();

    public int getDiningTable() {
        return diningTable;
    }

    public void setDiningTable(int diningTable) {
        this.diningTable = diningTable;
    }

    public Map<String, Integer> getFoodDic() {
        return foodDic;
    }

    public void setFoodDic(String name, Integer num) {
        foodDic.put(name, num);
    }
}

Chef 类:

public class Chef {
    public void makeFood(int num, String foodName) {
        System.out.println(num + "份" + foodName);
    }

    public void cancelMakeFood(String orderName) {
        System.out.println("取消" + orderName);
    }
}

Waitor 类:

public class Waitor {
    private List<Command> commands;
    private List<Command> undoCommands;

    public Waitor() {
        commands = new ArrayList<>();
        undoCommands = new ArrayList<>();
    }

    public void setCommand(Command cmd){
        commands.add(cmd);
    }

    public void setUndoCommands(Command cmd) {
        undoCommands.add(cmd);
    }

    public void orderUp() {
        System.out.println("服务员:叮咚,大厨,新订单来了.......");
        for (int i = 0; i < commands.size(); i++) {
            Command cmd = commands.get(i);
            if (cmd != null) {
                cmd.execute();
            }
        }
    }

    public void cancelOrder() {
        for (int i = 0; i < undoCommands.size(); i++) {
            Command undoCmd = undoCommands.get(i);
            if (undoCmd != null) {
                undoCmd.undo();
            }
        }
    }
}

Client 类:

public class Client {
    public static void main(String[] args) {
        // 创建两个订单
        Order order1 = new Order();
        order1.setDiningTable(1);
        order1.setFoodDic("西红柿鸡蛋面", 1);
        order1.setFoodDic("小杯可乐", 1);

        Order order2 = new Order();
        order2.setDiningTable(2);
        order2.setFoodDic("红烧排骨", 2);
        order2.setFoodDic("柠檬水", 2);

        // 创建接收者
        Chef receiver = new Chef();
        // 将订单和接收者封装成命令对象
        OrderCommand cmd1 = new OrderCommand(receiver, order1);
        OrderCommand cmd2 = new OrderCommand(receiver, order2);
        // 创建调用者 waitor
        Waitor invoker = new Waitor();
        invoker.setCommand(cmd1);
        invoker.setCommand(cmd2);

        // 撤销订单的命令
        invoker.setUndoCommands(cmd2);

        invoker.orderUp();
        invoker.cancelOrder();
    }
}

命令模式在 Spring 框架中的 JdbcTemplate 源码中的应用

  • query 方法中的返回值类型 StatementCallback 就是一个命令接口 Command.
  • 内部匿名类 QueryStatementCallback 就是一个具体的命令类同时也是命令接收者,实现了 doInStatement 方法
  • 命令调用者就是 JdbcTemplate 类,在 execute 方法中调用了命令接口的 doInStatement 方法

StatementCallback 接口:

public interface StatementCallback<T> {
    @Nullable
    T doInStatement(Statement var1) throws SQLException, DataAccessException;
}

JdbcTemplate 类:

public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
	// ...
	@Nullable
    public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException {
        Assert.notNull(sql, "SQL must not be null");
        Assert.notNull(rse, "ResultSetExtractor must not be null");
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Executing SQL query [" + sql + "]");
        }

        class QueryStatementCallback implements StatementCallback<T>, SqlProvider 		{
            QueryStatementCallback() {
            }

            @Nullable
            public T doInStatement(Statement stmt) throws SQLException {
                ResultSet rs = null;

                Object var3;
                try {
                    rs = stmt.executeQuery(sql);
                    var3 = rse.extractData(rs);
                } finally {
                    JdbcUtils.closeResultSet(rs);
                }

                return var3;
            }

            public String getSql() {
                return sql;
            }
        }

        return this.execute((StatementCallback)(new QueryStatementCallback()));
    }
    @Nullable
    public <T> T execute(StatementCallback<T> action) throws DataAccessException {
        Assert.notNull(action, "Callback object must not be null");
        Connection con = DataSourceUtils.getConnection(this.obtainDataSource());
        Statement stmt = null;

        Object var11;
        try {
            stmt = con.createStatement();
            this.applyStatementSettings(stmt);
            T result = action.doInStatement(stmt);
            this.handleWarnings(stmt);
            var11 = result;
        } catch (SQLException var9) {
            String sql = getSql(action);
            JdbcUtils.closeStatement(stmt);
            stmt = null;
            DataSourceUtils.releaseConnection(con, this.getDataSource());
            con = null;
            throw this.translateException("StatementCallback", sql, var9);
        } finally {
            JdbcUtils.closeStatement(stmt);
            DataSourceUtils.releaseConnection(con, this.getDataSource());
        }

        return var11;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/147337.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Java开发】Spring Cloud 03 :Spring Boot 项目搭建

为了体验从 0 到 1 的微服务改造过程&#xff0c;我们先使用 Spring Boot 搭建一个基础版的优惠券平台项目&#xff0c;等学习到 Spring Cloud 的时候&#xff0c;我们就在这个项目之上做微服务化改造&#xff0c;将 Spring Cloud 的各个组件像添砖加瓦一样集成到项目里。上一章…

jacoco:java代码覆盖率实践

文章目录一、jacoco基本了解二、实践准备三、jacoco使用3.1 插桩3.2 dump:覆盖率文件导出3.3 report:可视化报告3.4 merge:合并覆盖率文件四、相关命令扩展4.1 javaagent4.2 dump4.3 merge4.4 report五、资源链接一、jacoco基本了解 jacoco是一款面向java的代码覆盖率工具&…

linux系统中C++中构造与析构函数以及this的使用方法

大家好&#xff0c;今天主要和大家聊一聊&#xff0c;C里面的基本语法结构以及对应的操作方法。 目录 第一&#xff1a;构造函数与析构函数 第二&#xff1a;this指针 第一&#xff1a;构造函数与析构函数 什么是构造函数&#xff1f;构造函数在对象实例化时被系统自动调用&a…

xshell连接Linux一直失败解决方法

文章目录解决对象方法配置防火墙关闭Linux防火墙关闭Windows防火墙xshell连接Linux一直失败解决方法 解决对象 可能出现以下两个问题&#xff1a; Linux防火墙已关闭和Windows防火墙已经关闭配置好 vim /etc/sysconfig/network-scripts/ifcfg-ens33 方法 配置 这个是最容易…

linux系统中实现C++中继承和重载的方法

大家好&#xff0c;今天主要和大家聊一聊&#xff0c;如何实现C中继承和重载的功能。 第一&#xff1a;C中的继承功能 面向对象程序设计中最重要的一个概念是继承。继承允许我们依据另一个类来定义一个类&#xff0c;这使得创建和维护一个应用程序变得更容易。这样做&#xff0…

CLRNet: Cross Layer Refinement Network for Lane Detection

Paper name CLRNet: Cross Layer Refinement Network for Lane Detection Paper Reading Note URL: https://arxiv.org/pdf/2203.10350.pdf TL;DR CVPR 2022 文章&#xff0c;自动驾驶公司飞步科技与浙大联合出品。lane anchor-based 方案&#xff0c;在多个数据集上取得 …

Linux中的哈希表:基于双链表的内核模块

1. 前言Linux内核中选取双向链表作为其基本的数据结构&#xff0c;并将其嵌入到其他的数据结构中&#xff0c;使得其他的数据结构不必再一一实现其各自的双链表结构。实现了双链表结构的统一&#xff0c;同时可以演化出其他复杂数据结构。本文对linux中基于双链表实现的哈希表进…

java springboot+mybatis电影售票网站管理系统前台+后台设计和实现

java springbootmybatis电影售票网站管理系统前台后台设计和实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言…

RS—|遥感数字图像处理编程练习(python)

目录一&#xff1a;模拟计算图像直方图和累计直方图二&#xff1a;计算图像的均值、标准差、相关系数和协方差三&#xff1a;利用模板进行卷积运算四&#xff1a;获取彩色图像的直方图五&#xff1a;图像直方图均衡化一&#xff1a;模拟计算图像直方图和累计直方图 ① 调用的p…

【雷达入门 | FMCW毫米波雷达系统的性能参数分析】

本文编辑&#xff1a;调皮哥的小助理 FMCW毫米波雷达系统的性能参数主要包含&#xff1a; (1)距离估计、距离分辨率、距离精度、最大探测距离; (2)速度估计、速度分辨率、速度精度、最大不模糊速度&#xff1b; (3)角度估计、角度分辨率、角度精度、最大角度范围。 分析以及…

微服务框架SpringCloud从入门到通神(持续更新)

SpringCloud——>SpringBoot——>JavaWeb 微服务技术栈导学1 哔站up黑马程序员主讲老师&#xff0c;一上来就给介绍了SpringCloud出现的背景&#xff1a;微服务是分布式架构的一种&#xff0c;分布式架构就是要把服务做拆分&#xff0c;而SpringCloud只是解决了服务拆分式…

FTP协议原理简析

FTP服务器默认使用TCP协议的20、21端口与客户端进行通信。21端口用于建立控制连接&#xff0c;并传输FTP指令。20端口用于建立数据连接&#xff0c;传输数据流。 一&#xff1a;FTP功能简介 1&#xff1a;FTP服务器能够进行档案的传输与管理功能&#xff1b; 2&#xff1a;可以…

招生简章 | 欢迎报考中科院空天院网络信息体系技术重点实验室(七室)

官方公众号链接&#xff1a;招生简章 | 欢迎报考中科院空天院网络信息体系技术重点实验室&#xff08;七室&#xff09; 招生简章 | 欢迎报考中科院空天院网络信息体系技术重点实验室&#xff08;七室&#xff09; 中国科学院空天信息创新研究院&#xff08;简称空天院&#x…

【实战篇】38 # 如何使用数据驱动框架 D3.js 绘制常用数据图表?

说明 【跟月影学可视化】学习笔记。 图表库 vs 数据驱动框架 图表库只要调用 API 就能展现内容&#xff0c;灵活性不高&#xff0c;对数据格式要求也很严格&#xff0c;但方便数据驱动框架需要手动去完成内容的呈现&#xff0c;灵活&#xff0c;不受图表类型对应 API 的制约…

Smart Finance成为火必投票竞选项目,参与投票获海量奖励

最近&#xff0c;Huobi推出了新一期的“投票上币”活动&#xff0c;即用户可以通过HT为候选项目投票&#xff0c;在投票截止后&#xff0c;符合条件的优质项目将直接上线Huobi。而Smart Finance成为了新一期投票上币活动的竞选项目之一&#xff0c;并备受行业关注&#xff0c;与…

C++ 命令模式

什么是命令模式&#xff1f; 将请求转换为一个包含与请求相关的所有信息的独立对象。从而使你可以用不同的请求方法进行参数化&#xff0c;并且能够对请求进行排队、记录请求日志以及撤销请求操作。命令模式属于行为设计模式 如何理解命令模式 命令模式很像我们订外卖&#…

Hudi(10):Hudi集成Spark之并发控制

目录 0. 相关文章链接 1. Hudi支持的并发控制 1.1. MVCC 1.2. OPTIMISTIC CONCURRENCY 2. 使用并发写方式 3. 使用Spark DataFrame并发写入 4. 使用Delta Streamer并发写入 0. 相关文章链接 Hudi文章汇总 1. Hudi支持的并发控制 1.1. MVCC Hudi的表操作&#xff0c;如…

阿里云 EDAS Java服务日志中打印调用链TraceId

最近要搭建阿里云的日志服务SLS&#xff0c;收集服务日志&#xff0c;进行统一的搜索查询。但遇到一个问题如何在日志中打印链路的TraceId&#xff0c;本文章记录一下对EDAS免费的解决方法。 先看一下阿里官方文档 业务日志关联调用链的TraceId信息 从文档上看&#xff0c;想要…

基于SSM的资源发布系统

项目介绍&#xff1a; 该系统基于SSM技术&#xff0c;数据层为MyBatis&#xff0c;数据库使用mysql&#xff0c;MVC模式&#xff0c;B/S架构&#xff0c;具有完整的业务逻辑。系统共分为管理员&#xff0c;用户两种角色&#xff0c;主要功能&#xff1a;登陆注册&#xff0c;用…

数据结构:跳表

文章目录跳表跳表的由来单链表的查找效率太低提高单链表的查找效率跳表的时间复杂度分析跳表的空间复杂度分析跳表的插入操作跳表的删除操作跳表索引动态更新跳表 对链表进行改造&#xff0c;在链表上加多级索引的结构就是跳表&#xff0c;使其可以支持类似“二分”的查找算法。…