在软件规划中,指令形式是一种非常重要的规划形式。随着软件体系的不断发展,体系中的各个组件之间的耦合度越来越高,这会导致体系的复杂度和保护难度不断添加。为了处理这个问题,规划形式供给了很多处理方案,其间指令形式就是其间之一。

指令形式将恳求操作封装成一个独立的目标,使得恳求的发送者和接纳者目标之间解耦。经过这种办法,指令形式能够进步体系的灵敏性、可保护性和可扩展性,然后降低了体系的耦合度。在实际的软件规划中,指令形式被广泛应用于各种应用场景,如图形界面开发、网络通信、电子商务体系等。它能够帮助开发人员快速地完结各种恳求操作,而且能够支撑吊销和重做操作,进步了体系的交互性和用户体验。

什么是指令形式

官方文档描述:

指令形式将恳求封装为一个目标,然后使得你能够经过不同的恳求参数化客户端,将恳求进行排队或记载,并支撑可吊销的操作。

The Command pattern encapsulates a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.

指令形式的效果:

  1. 将恳求发送者和恳求接纳者进行解耦,然后削减它们之间的依赖联系,进步体系的灵敏性和可扩展性。

  2. 支撑吊销、重做和事务性操作,使得体系愈加强健和可靠。

  3. 支撑指令的排队和记载,然后能够更好地办理和操控恳求的履行次序和时刻。

  4. 使得代码更易于扩展和保护,因为每个指令目标都只封装了一次恳求操作,而不需求修正恳求发送者或恳求接纳者
    的代码。

指令形式的结构

  • 指令接口(Command):界说履行操作的接口。
  • 详细指令(ConcreteCommand):完结指令接口,绑定接纳者和一个动作。
  • 履行者(Invoker):调用指令目标以履行恳求。
  • 接纳者(Receiver):履行与恳求相关的操作。

指令形式完结

一个常见的生活中的比如是运用遥控器操控电视机。遥控器能够被看做是一个指令目标,它封装了各种详细的恳求,例如翻开电视、封闭电视、切换频道等。电视机则是一个接纳者目标,它知道怎么履行这些恳求操作。

当我们按下遥控器上的按钮时,遥控器会将相应的恳求封装成一个指令目标,并将该目标发送给电视机进行处理。这样,电视机就不需求知道详细的恳求发送者是谁,也不需求知道怎么处理这些恳求。经过将恳求封装成一个独立的目标,我们能够愈加灵敏地办理和操控恳求的履行次序和时刻。

指令接口(Command):界说履行操作的接口

public interface Command {
    void execute();
}

详细指令(ConcreteCommand):完结指令接口,绑定接纳者一个动作

public class TurnOnCommand implements Command {
    private Television tv;
    // 结构函数,用于将接纳者目标传递给指令目标
    public TurnOnCommand(Television tv) {
        this.tv = tv;
    }
    // 履行翻开电视机指令
    public void execute() {
        tv.turnOn();
    }
}
public class TurnOffCommand implements Command {
    private Television tv;
    // 结构函数,用于将接纳者目标传递给指令目标
    public TurnOffCommand(Television tv) {
        this.tv = tv;
    }
    // 履行封闭电视机指令
    public void execute() {
        tv.turnOff();
    }
}
public class ChangeChannelCommand implements Command {
    private Television tv;
    private int channel;
    // 结构函数,用于将接纳者目标和指令参数传递给指令目标
    public ChangeChannelCommand(Television tv, int channel) {
        this.tv = tv;
        this.channel = channel;
    }
    // 履行切换频道指令
    public void execute() {
        tv.changeChannel(channel);
    }
}

履行者(Invoker):调用指令目标以履行恳求

public class RemoteControl {
    private Command[] commands;
    public RemoteControl(Command[] commands) {
        this.commands = commands;
    }
    public void pressButton(int index) {
        if (index >= 0 && index < commands.length) {
            commands[index].execute();
        }
    }
}

这个类是指令形式中的调用者(Invoker)类,它包含一个指令数组,能够经过调用指令目标的execute()办法来履行指令操作。在这个类中,经过调用pressButton()办法来履行详细的指令操作。它接纳一个整数参数index,表明要履行的指令目标的索引,然后经过索引获取对应的指令目标,然后调用该指令目标的execute()办法来履行指令操作。

接纳者(Receiver):履行与恳求相关的操作

public class Television {
    private int currentChannel = 1;
    private boolean isOn = false;
    // 翻开电视机
    public void turnOn() {
        isOn = true;
        System.out.println("电视机已翻开");
    }
    // 封闭电视机
    public void turnOff() {
        isOn = false;
        System.out.println("电视机已封闭");
    }
    // 切换频道
    public void changeChannel(int channel) {
        if (isOn) {
            currentChannel = channel;
            System.out.println("已切换到频道 " + channel);
        } else {
            System.out.println("电视机未翻开");
        }
    }
    // 获取当时频道
    public int getCurrentChannel() {
        return currentChannel;
    }
    // 判别电视机是否翻开
    public boolean isOn() {
        return isOn;
    }
}
  • turnOn() 办法用于翻开电视机。
  • turnOff() 办法用于封闭电视机。
  • changeChannel(int channel) 办法用于切换频道。假如电视机现已翻开,则将当时频道设置为指定的频道,并输出一条提示信息;不然输出一条错误信息。
  • getCurrentChannel() 办法用于获取当时频道。
  • isOn() 办法用于判别电视机是否翻开。`

Client:调用代码

public class Client {
    public static void main(String[] args) {
        Television tv = new Television();
        Command[] commands = new Command[] {
                new TurnOnCommand(tv),
                new TurnOffCommand(tv),
                new ChangeChannelCommand(tv, 1),
                new ChangeChannelCommand(tv, 2),
                new ChangeChannelCommand(tv, 3)
        };
        RemoteControl remote = new RemoteControl(commands);
        remote.pressButton(0); // 翻开电视机
        remote.pressButton(2); // 切换到频道1
        remote.pressButton(3); // 切换到频道2
        remote.pressButton(4); // 切换到频道3
        remote.pressButton(1); // 封闭电视机
    }
}

指令形式的优缺点

指令形式的长处

  1. 解耦:指令形式将恳求发送者和接纳者目标解耦,使得它们不需求了解互相的存在,然后降低了体系的耦合度。例如,在一个智能家居体系中,经过指令形式,用户能够运用一个统一的遥控器来操控多种家电设备,而无需为每种设备独自配置操控器。

解耦指的是在软件规划中,将不同的组件之间的依赖联系降低到最小程度,使得它们能够独立地进行修正、扩展和保护。这样,当体系中的一个组件发生变化时,不会对其他组件产生影响,然后进步了体系的灵敏性和可保护性。

比喻来说,就像是拼积木一样,把积木拼接成独立的小块,使得每个小块能够独立拆卸和组合,而不会影响到其他的小块,然后进步了灵敏性和可保护性

  1. 可扩展性:指令形式支撑对恳求操作进行组合和分离,使得体系更容易扩展和保护。例如,在一个文本编辑器中,指令形式能够用于完结吊销、重做等功能。当需求添加新的文本操作时,只需创立一个新的指令类即可,无需修正现有代码。

  2. 可重用性:指令形式将恳求操作封装成一个独立的目标,使得这些目标能够被重复运用,然后进步了体系的可重用性。例如,在一个图形绘制程序中,能够运用指令形式来保存用户的绘图操作,以便在需求时重新履行或吊销这些操作。

  3. 安全性:指令形式能够将恳求操作的调用者和接纳者目标解耦,使得体系愈加安全可靠。例如,在一个在线付出体系中,能够运用指令形式来封装付出操作,然后保证付出恳求的正确性和安全性。

指令形式的缺点

  1. 添加体系复杂度:指令形式需求界说多个类和目标来完结详细的恳求操作,这或许会添加体系的复杂度和了解难度。例如,在一个简单的应用程序中,引入指令形式或许会导致过度规划,添加了不必要的开发和保护成本。

  2. 指令类或许过多:当体系中需求完结大量的详细恳求操作时,或许会导致指令类过多,然后添加了体系的保护难度和开发成本。例如,在一个具有复杂功能的企业级应用程序中,或许需求完结数百个不同的指令类,这将大大添加代码的复杂性和办理难度。

  3. 功能问题:因为指令形式需求将恳求操作封装成目标,因此或许会对体系的功能产生必定的影响。特别是在需求频繁履行恳求操作时,或许会导致体系的功能下降。例如,在一个高并发的网络服务器中,运用指令形式或许会添加目标的创立和毁掉开支,然后降低服务器的响应速度

指令形式在源码中的体现

spring结构

JdbcTemplate

JdbcTemplate是Spring结构中的核心组件之一,它供给了对数据库的操作接口,包含查询、更新、删除等操作。在JdbcTemplate中,运用指令形式来封装对数据库的操作,详细完结是经过将SQL句子和操作参数封装成一个目标,然后经过履行这个目标来完结数据库操作。

在JdbcTemplate中,指令形式的完结主要是经过三个接口来完结的:PreparedStatementCreatorPreparedStatementSetterRowMapper

首先是PreparedStatementCreator接口,它界说了一个用于创立PreparedStatement目标的办法createPreparedStatement(Connection con),其间con参数表明要运用的数据库衔接目标。这个接口代表了指令形式中的抽象指令,它封装了SQL句子和操作参数,而且经过createPreparedStatement办法将它们转化成一个PreparedStatement目标。

接下来是PreparedStatementSetter接口,它界说了一个用于设置PreparedStatement目标参数的办法setValues(PreparedStatement ps),其间ps参数表明要设置的PreparedStatement目标。这个接口代表了指令形式中的详细指令,它接纳一个PreparedStatement目标作为参数,而且经过setValues办法来设置PreparedStatement目标的参数。

最后是RowMapper接口,它界说了一个用于将ResultSet成果集转化成Java目标的办法mapRow(ResultSet rs, int rowNum),其间rs参数表明要转化的ResultSet成果集,rowNum参数表明成果集的当时行号。这个接口代表了指令形式中的接纳者,它接纳一个ResultSet目标作为参数,而且经过mapRow办法来将成果集转化成Java目标并回来。

在JdbcTemplate中,经过将详细指令(PreparedStatementSetter接口的完结类)和抽象指令(PreparedStatementCreator接口的完结类)作为参数传递给query办法,而且在办法内部调用它们的办法来完结详细的数据库操作。同时,也经过将RowMapper接口的完结类作为参数传递给query办法,而且在办法内部调用它的办法来将成果集转化成Java目标并回来。

经过这种办法,JdbcTemplate完结了对数据库操作的封装,而且将指令目标与详细操作解耦,使得代码愈加灵敏和可扩展。同时,也使得代码愈加易于保护和重构,进步了软件开发的功率。

总归,指令形式是一种非常有用的规划形式,经过将恳求封装为一个目标,使得体系愈加灵敏、可扩展和易于保护。