《设计模式》命令模式

简介: 《设计模式》命令模式

《设计模式》命令模式

定义

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

命令模式的优缺点

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

命令模式的使用场景

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

命令模式的角色组成:

抽象命令(Command):定义命令的接口,声明执行的方法。

具体命令(Concrete Command):具体的命令实现命令接口,通常会持有接收者,并调

用接收者的功能来完成命令要执行的操作。

实现者/接收者(Receiver):接收者是真正执行命令的对象,任何类都可能成为一个接收

者,只要它能够实现命令要求实现的相应功能。

调用者/请求者(Invoker):调用命令对象执行请求,通常会持有命令对象,可以持有很

多的命令对象。

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

bbf9a817e45e4f2abc144b1ae027e138.png

案例背景:

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

关系类图如下所示

bbf9a817e45e4f2abc144b1ae027e138.png

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;
    }
}
相关文章
|
7月前
|
设计模式 UED
二十三种设计模式:解锁软件开发的神器:命令模式与撤销重做功能
二十三种设计模式:解锁软件开发的神器:命令模式与撤销重做功能
182 0
|
3月前
|
设计模式 存储 算法
Java设计模式-命令模式(16)
Java设计模式-命令模式(16)
|
4月前
|
设计模式 存储 Java
【十二】设计模式~~~行为型模式~~~命令模式(Java)
文章详细介绍了命令模式(Command Pattern),这是一种对象行为型模式,用于将请求封装成对象,实现请求发送者与接收者的解耦,从而降低系统耦合度、提高灵活性,并支持命令的排队、记录、撤销和恢复操作。通过案例分析、结构图、时序图和代码示例,文章展示了命令模式的组成部分、实现方式和应用场景,并讨论了其优点、缺点和适用情况。
|
5月前
|
设计模式 JavaScript API
js设计模式【详解】—— 命令模式
js设计模式【详解】—— 命令模式
47 6
|
6月前
|
设计模式
命令模式-大话设计模式
命令模式-大话设计模式
|
6月前
|
设计模式 Java uml
必知的技术知识:JAVA【设计模式】命令模式
必知的技术知识:JAVA【设计模式】命令模式
30 0
|
6月前
|
设计模式 Java
Java设计模式之命令模式详解
Java设计模式之命令模式详解
|
6月前
|
设计模式
设计模式之命令模式
设计模式之命令模式
|
7月前
|
设计模式 Java 调度
【设计模式系列笔记】命令模式
命令模式是一种行为设计模式,它将请求封装成一个对象,从而允许使用不同的请求、队列或日志请求参数化客户端对象,同时支持撤销操作。
73 1
|
7月前
|
设计模式 Java 调度
小谈设计模式(24)—命令模式
小谈设计模式(24)—命令模式