当前位置:主页 > 查看内容

设计模式:行为型-命令模式

发布时间:2021-06-16 00:00| 位朋友查看

简介:目录 第一章 命令模式介绍 第二章 命令模式实现 2.1、抽象命令类 2.2、具体命令类 2.3、命令接收者 2.4、命令请求者 2.5、最终测试类 第三章 命令模式应用 项目地址https://gitee.com/caochenlei/design-pattern 第一章 命令模式介绍 命令模式的介绍 在软件……


项目地址:https://gitee.com/caochenlei/design-pattern

第一章 命令模式介绍

命令模式的介绍:

在软件开发系统中,“方法的请求者”与“方法的实现者”之间经常存在紧密的耦合关系,这不利于软件功能的扩展与维护。例如,想对方法进行“撤销、重做、记录”等处理都很不方便,因此“如何将方法的请求者与实现者解耦”变得很重要,命令模式就能很好地解决这个问题。

在现实生活中,命令模式的例子也很多。比如看电视时,我们只需要轻轻一按遥控器就能完成频道的切换,这就是命令模式,将换台请求和换台处理完全解耦了。电视机遥控器(命令发送者)通过按钮(具体命令)来遥控电视机(命令接收者)。

命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。

命令模式的优点:

  • 通过引入中间件(抽象接口)降低系统的耦合度。
  • 扩展性良好,增加或删除命令非常方便。采用命令模式增加与删除命令不会影响其他类,且满足“开闭原则”。
  • 可以实现宏命令。命令模式可以与组合模式结合,将多个命令装配成一个组合命令,即宏命令。
  • 方便实现 Undo 和 Redo 操作。命令模式可以与后面介绍的备忘录模式结合,实现命令的撤销与恢复。
  • 可以在现有命令的基础上,增加额外功能。比如日志记录,结合装饰器模式会更加灵活。

命令模式的缺点:

  • 可能产生大量具体的命令类。因为每一个具体操作都需要设计一个具体命令类,这会增加系统的复杂性。
  • 命令模式的结果其实就是接收方的执行结果,但是为了以命令的形式进行架构、解耦请求与实现,引入了额外类型结构(引入了请求方与抽象命令接口),增加了理解上的困难。不过这也是设计模式的通病,抽象必然会额外增加类的数量,代码抽离肯定比代码聚合更加难理解。

命令模式的场景:

  • 请求调用者需要与请求接收者解耦时,命令模式可以使调用者和接收者不直接交互。
  • 系统随机请求命令或经常增加、删除命令时,命令模式可以方便地实现这些功能。
  • 当系统需要执行一组操作时,命令模式可以定义宏命令来实现该功能。
  • 当系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作时,可以将命令对象存储起来,采用备忘录模式来实现。

命令模式的角色:

  • 抽象命令类(Command)角色:声明执行命令的接口,拥有执行命令的抽象方法 execute()。
  • 具体命令类(Concrete Command)角色:是抽象命令类的具体实现类,它拥有接收者对象,并通过调用接收者的功能来完成命令要执行的操作。
  • 实现者/接收者(Receiver)角色:执行命令功能的相关操作,是具体命令对象业务的真正实现者。
  • 调用者/请求者(Invoker)角色:是请求的发送者,它通常拥有很多的命令对象,并通过访问命令对象来执行相关请求,它不直接访问接收者。

第二章 命令模式实现

2.1、抽象命令类

Command

public interface Command {
    //执行动作(操作)
    public void execute();

    //撤销动作(操作)
    public void undo();
}

2.2、具体命令类

NoCommand

public class NoCommand implements Command {
    @Override
    public void execute() {

    }

    @Override
    public void undo() {

    }
}

TVOnCommand

public class TVOnCommand implements Command {
    TVReceiver tv;

    public TVOnCommand(TVReceiver tv) {
        this.tv = tv;
    }

    @Override
    public void execute() {
        tv.on();
    }

    @Override
    public void undo() {
        tv.off();
    }
}

TVOffCommand

public class TVOffCommand implements Command {
    TVReceiver tv;

    public TVOffCommand(TVReceiver tv) {
        this.tv = tv;
    }

    @Override
    public void execute() {
        tv.off();
    }

    @Override
    public void undo() {
        tv.on();
    }
}

2.3、命令接收者

TVReceiver

public class TVReceiver {
    public void on() {
        System.out.println(" 电视机打开了... ");
    }

    public void off() {
        System.out.println(" 电视机关闭了... ");
    }
}

2.4、命令请求者

RemoteController

public class RemoteController {
    Command[] onCommands;   //开命令集合
    Command[] offCommands;  //关命令集合
    Command undoCommand;    //撤销命令

    public RemoteController() {
        onCommands = new Command[5];
        offCommands = new Command[5];

        for (int i = 0; i < 5; i++) {
            onCommands[i] = new NoCommand();
            offCommands[i] = new NoCommand();
        }
    }

    //设置命令按钮
    public void setCommand(int no, Command onCommand, Command offCommand) {
        onCommands[no] = onCommand;
        offCommands[no] = offCommand;
    }

    //按下开按钮
    public void onButtonWasPushed(int no) {
        //找到你按下的开的按钮,并调用对应方法
        onCommands[no].execute();
        //记录这次的操作,用于撤销
        undoCommand = onCommands[no];
    }

    //按下关按钮
    public void offButtonWasPushed(int no) {
        //找到你按下的关的按钮,并调用对应方法
        offCommands[no].execute();
        //记录这次的操作,用于撤销
        undoCommand = offCommands[no];
    }

    //按下撤销按钮
    public void undoButtonWasPushed() {
        undoCommand.undo();
    }
}

2.5、最终测试类

Client

public class Client {
    public static void main(String[] args) {
        //创建远程遥控器
        RemoteController remoteController = new RemoteController();
        //创建电视机接收者
        TVReceiver tvReceiver = new TVReceiver();
        TVOffCommand tvOffCommand = new TVOffCommand(tvReceiver);
        TVOnCommand tvOnCommand = new TVOnCommand(tvReceiver);
        remoteController.setCommand(0, tvOnCommand, tvOffCommand);
        //调用电视机的操作
        remoteController.onButtonWasPushed(0);
        remoteController.offButtonWasPushed(0);
        remoteController.undoButtonWasPushed();
    }
}
 电视机打开了... 
 电视机关闭了... 
 电视机打开了... 

第三章 命令模式应用

Spring 框架的 JdbcTemplate 就使用到了命令模式,不过并不是命令模式的标准实现,只是用到了命令模式的思想。

StatementCallback充当了抽象命令类。

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

以下图片中是实现了StatementCallback的所有具体命令类。

这里QueryStatementCallback使用到了匿名内部类而不是单独写成一个类文件,它实现了命令接口, 同时也充当命令接收者。

@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(new QueryStatementCallback(), true);
}

命令调用者是 JdbcTemplate,其中 execute(StatementCallback<T> action, boolean closeResources) 方法中,调用 action.doInStatement(stmt) 方法,不同的实现 StatementCallback 接口的对象,对应不同的 doInStatemnt 实现逻辑。

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

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

    }

    return var12;
}
;原文链接:https://blog.csdn.net/qq_38490457/article/details/115567490
本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!

推荐图文


随机推荐