设计模式之命令模式

RAG——RAG 索引(文档解析技术) 本文介绍了RAG系统中文档解析的关键技术,重点分析了如何通过LangChain的Document Loaders处理多种格式文档。文章指出高质量文档解析对RAG系统效果的决定性作用,并详细讲解了PDF、TXT、Word等常见格式的解析方法。作者提供了代码示例和Gitee开源项目链接,特别强调了PDF解析的深入方案,同时介绍了相关依赖库的安装配置。文章还展示了如何定义通用文档加载方法,为开发者提供了实用的技术参考。 阅读详情

概念

命令模式是一种行为型设计模式,它将请求封装成一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。

定义

命令模式把一个请求或者操作封装到一个对象中,将发出命令的责任和执行命令的责任分割开。这样,命令的发送者不需要知道命令的接收者是谁,也不需要知道命令是如何被执行的,只需要关心如何发出命令。而命令的接收者只需要专注于如何执行命令,实现具体的业务逻辑。

想象一下,此时你手里握着一个智能家居的遥控器,可以控制家里的各种设备(灯、空调、音响)。最初,遥控器的每个按钮直接绑定了设备的操作——比如“开灯”按钮直接硬编码调用了客厅灯.turnOn() 的方法。这种方法看似简单,但是当设备升级的时候(比如换用语音控制的智能灯),你就需要拆开遥控器重新焊接电路;想新增一个“观影模式”(开灯、开空调、关窗帘)时,你又需要继续再遥控器内新增一堆新逻辑。而命令模式(Command) 则是把每一个操作(如开灯、调节温度)封装成独立的 命令对象,例如LightOnCommand包含执行(execute())和撤销(undo())方法,内部持有对灯具的引用。遥控器(调用者)完全无需知道设备细节,只需存储并触发这些命令对象。当你按下“开灯”按钮时,遥控器只是调用lightCommand.execute(),具体是传统灯具还是智能灯执行,它毫不关心。

那么,在这样的设计模式下,就会体现出下述三个优点:

  1. 灵活扩展:新增空调控制,只需创建一个AirconCommand丢给遥控器,无需改动原有代码;
  2. 支持宏命令:将关灯、开空调、降窗帘组合成MovieModeCommand,一键触发复杂操作;
  3. 实现撤销功能:执行命令后,遥控器记录历史,按下“撤销”键即可回退到上一步状态。

这就是命令模式的核心——将“请求”抽象为对象,让调用者和接收者解耦。

组成部分

  • 命令接口(Command):声明了执行命令的抽象方法,所有具体命令类都需要实现这个接口。它定义了一个统一的执行命令的方法,通常命名为execute等,用来规范具体命令类的行为。
  • 具体命令类(ConcreteCommand):实现了命令接口,持有一个接收者对象的引用,在execute方法中调用接收者的相关方法来完成具体的操作。它将命令的执行和接收者的具体行为绑定在一起,实现了命令的具体逻辑。
  • 接收者(Receiver):知道如何执行与请求相关的操作,具体命令对象会调用它的方法来完成命令的执行。它是真正执行命令的对象,负责实现命令所对应的具体业务逻辑。
  • 调用者(Invoker):负责调用命令对象的execute方法来发起命令。它不直接与接收者交互,而是通过命令对象来间接执行操作,它可以设置命令对象,并在需要的时候触发命令的执行。
  • 客户端(Client):创建具体命令对象,并设置命令对象的接收者。在客户端中,将命令的发送者和接收者进行解耦,使得发送者不需要了解接收者的具体实现,只需要关心命令的发送。

在这里插入图片描述

工作原理

  1. 定义接口:先定义一个命令接口,声明execute等方法规范命令行为。
  2. 创建具体命令类:创建实现命令接口的具体命令类,内部持有接收者对象,在execute方法中调用接收者方法完成具体操作。
  3. 设置接收者:创建接收者对象,它负责执行具体业务逻辑,具体命令类将其作为成员变量持有。
  4. 设置调用者:创建调用者,它持有命令对象,通过调用命令对象的execute方法来发起命令,并不直接与接收者交互。
  5. 客户端操作:客户端负责创建具体命令对象,设置好接收者,并将命令对象传递给调用者。
  6. 命令执行:调用者执行命令时,命令对象调用接收者的相应方法完成操作,实现请求发送者和接收者的解耦。若支持撤销,命令对象会记录执行前状态,在撤销时调用接收者方法恢复状态。

示例

我么使用智能家居遥控器的例子来编写示例代码。

类图

在这里插入图片描述

C++实现

#include <iostream>
#include <vector>

// 前向声明
class Receiver;

// 命令接口
class Command {
public:
    virtual void execute() = 0;
    virtual void undo() = 0;
    virtual ~Command() = default;
};

// 接收者:灯具
class Light {
public:
    void turnOn() {
        std::cout << "Light is on." << std::endl;
    }
    void turnOff() {
        std::cout << "Light is off." << std::endl;
    }
};

// 接收者:空调
class AirConditioner {
public:
    void turnOn() {
        std::cout << "Air conditioner is on." << std::endl;
    }
    void turnOff() {
        std::cout << "Air conditioner is off." << std::endl;
    }
};

// 开灯命令
class LightOnCommand : public Command {
private:
    Light* light;
public:
    explicit LightOnCommand(Light* light) : light(light) {}
    void execute() override {
        light->turnOn();
    }
    void undo() override {
        light->turnOff();
    }
};

// 关灯命令
class LightOffCommand : public Command {
private:
    Light* light;
public:
    explicit LightOffCommand(Light* light) : light(light) {}
    void execute() override {
        light->turnOff();
    }
    void undo() override {
        light->turnOn();
    }
};

// 开空调命令
class AirConditionerOnCommand : public Command {
private:
    AirConditioner* ac;
public:
    explicit AirConditionerOnCommand(AirConditioner* ac) : ac(ac) {}
    void execute() override {
        ac->turnOn();
    }
    void undo() override {
        ac->turnOff();
    }
};

// 关空调命令
class AirConditionerOffCommand : public Command {
private:
    AirConditioner* ac;
public:
    explicit AirConditionerOffCommand(AirConditioner* ac) : ac(ac) {}
    void execute() override {
        ac->turnOff();
    }
    void undo() override {
        ac->turnOn();
    }
};

// 调用者:遥控器
class RemoteControl {
private:
    std::vector<Command*> commands;
    std::vector<Command*> undoCommands;
public:
    void setCommand(Command* command) {
        commands.push_back(command);
    }
    void pressButton(int index) {
        if (index < commands.size()) {
            commands[index]->execute();
            undoCommands.push_back(commands[index]);
        }
    }
    void pressUndoButton() {
        if (!undoCommands.empty()) {
            Command* lastCommand = undoCommands.back();
            lastCommand->undo();
            undoCommands.pop_back();
        }
    }
    ~RemoteControl() {
        for (auto command : commands) {
            delete command;
        }
    }
};

// 客户端代码
int main() {
    // 创建接收者
    Light light;
    AirConditioner ac;

    // 创建命令
    Command* lightOn = new LightOnCommand(&light);
    Command* lightOff = new LightOffCommand(&light);
    Command* acOn = new AirConditionerOnCommand(&ac);
    Command* acOff = new AirConditionerOffCommand(&ac);

    // 创建调用者
    RemoteControl remote;

    // 设置命令
    remote.setCommand(lightOn);
    remote.setCommand(lightOff);
    remote.setCommand(acOn);
    remote.setCommand(acOff);

    // 执行命令
    remote.pressButton(0); // 开灯
    remote.pressButton(2); // 开空调
    remote.pressUndoButton(); // 撤销开空调
    remote.pressUndoButton(); // 撤销开灯

    return 0;
}

Java实现

// 命令接口
interface Command {
    void execute();
    void undo();
}

// 接收者:灯具
class Light {
    public void turnOn() {
        System.out.println("Light is on.");
    }

    public void turnOff() {
        System.out.println("Light is off.");
    }
}

// 接收者:空调
class AirConditioner {
    public void turnOn() {
        System.out.println("Air conditioner is on.");
    }

    public void turnOff() {
        System.out.println("Air conditioner is off.");
    }
}

// 开灯命令
class LightOnCommand implements Command {
    private Light light;

    public LightOnCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.turnOn();
    }

    @Override
    public void undo() {
        light.turnOff();
    }
}

// 关灯命令
class LightOffCommand implements Command {
    private Light light;

    public LightOffCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.turnOff();
    }

    @Override
    public void undo() {
        light.turnOn();
    }
}

// 开空调命令
class AirConditionerOnCommand implements Command {
    private AirConditioner ac;

    public AirConditionerOnCommand(AirConditioner ac) {
        this.ac = ac;
    }

    @Override
    public void execute() {
        ac.turnOn();
    }

    @Override
    public void undo() {
        ac.turnOff();
    }
}

// 关空调命令
class AirConditionerOffCommand implements Command {
    private AirConditioner ac;

    public AirConditionerOffCommand(AirConditioner ac) {
        this.ac = ac;
    }

    @Override
    public void execute() {
        ac.turnOff();
    }

    @Override
    public void undo() {
        ac.turnOn();
    }
}

// 调用者:遥控器
class RemoteControl {
    private java.util.ArrayList<Command> commands = new java.util.ArrayList<>();
    private java.util.ArrayList<Command> undoCommands = new java.util.ArrayList<>();

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

    public void pressButton(int index) {
        if (index < commands.size()) {
            Command command = commands.get(index);
            command.execute();
            undoCommands.add(command);
        }
    }

    public void pressUndoButton() {
        if (!undoCommands.isEmpty()) {
            Command lastCommand = undoCommands.remove(undoCommands.size() - 1);
            lastCommand.undo();
        }
    }
}

// 客户端代码
public class Main {
    public static void main(String[] args) {
        // 创建接收者
        Light light = new Light();
        AirConditioner ac = new AirConditioner();

        // 创建命令
        Command lightOn = new LightOnCommand(light);
        Command lightOff = new LightOffCommand(light);
        Command acOn = new AirConditionerOnCommand(ac);
        Command acOff = new AirConditionerOffCommand(ac);

        // 创建调用者
        RemoteControl remote = new RemoteControl();

        // 设置命令
        remote.setCommand(lightOn);
        remote.setCommand(lightOff);
        remote.setCommand(acOn);
        remote.setCommand(acOff);

        // 执行命令
        remote.pressButton(0); // 开灯
        remote.pressButton(2); // 开空调
        remote.pressUndoButton(); // 撤销开空调
        remote.pressUndoButton(); // 撤销开灯
    }
}

代码解释

  1. Command 接口:定义了命令的基本操作,包括execute()用于执行命令和undo()用于撤销命令。
  2. 接收者类(Light 和 AirConditioner):这些类表示具体的设备,包含设备的基本操作方法,如turnOn()和turnOff()。
  3. 具体命令类(LightOnCommand、LightOffCommand、AirConditionerOnCommand、AirConditionerOffCommand):实现了Command接口,内部持有对接收者的引用,在execute()方法中调用接收者的相应操作,undo()方法则执行相反的操作。
  4. 调用者类(RemoteControl):负责存储和执行命令,通过setCommand()方法设置命令,pressButton()方法执行指定索引的命令,pressUndoButton()方法撤销上一个执行的命令。
  5. 客户端代码(main 函数):创建接收者、命令和调用者对象,设置命令并执行相应操作。

通过这种方式,遥控器(调用者)不需要知道具体设备的细节,只需要操作命令对象,提高了系统的可扩展性和可维护性。当设备升级或新增功能时,只需要创建新的命令类,而不需要修改遥控器的代码。

设计原则

命令模式主要遵循以下几个重要的设计原则:

单一职责原则(Single Responsibility Principle)

  • 解释:该原则强调一个类应该仅有一个引起它变化的原因。在命令模式中,每个类都有其明确的职责。
  • 具体体现
    • 命令接口和具体命令类:Command接口只负责定义命令的执行和撤销等操作规范,而具体的命令类(如LightOnCommand、LightOffCommand)只负责实现特定的命令逻辑,比如在execute方法中调用接收者的特定操作,它们不涉及其他无关的功能。
    • 接收者类:像Light或AirConditioner类,只专注于自身设备的具体操作,如开启、关闭等,不参与命令的管理和调用逻辑。
    • 调用者类:RemoteControl类只负责存储和执行命令,不关心命令具体如何实现以及接收者的具体操作细节。

开闭原则(Open/Closed Principle)

  • 解释:软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。即当需求发生变化时,应该通过扩展软件实体的行为来实现,而不是修改已有的代码。
  • 具体体现
    • 新增命令:当需要添加新的命令时,比如增加一个调节灯光亮度的命令,只需要创建一个新的具体命令类(如LightBrightnessCommand),实现Command接口,而不需要修改现有的Command接口、调用者类(RemoteControl)和接收者类(Light)。
    • 新增接收者:如果要引入新的设备,如智能窗帘,只需要创建新的接收者类(Curtain)和对应的命令类(如CurtainOpenCommand、CurtainCloseCommand),原有的系统结构和代码基本无需改动。

依赖倒置原则(Dependency Inversion Principle)

  • 解释:高层模块不应该依赖低层模块,二者都应该依赖抽象;抽象不应该依赖细节,细节应该依赖抽象。
  • 具体体现
    • 调用者与命令的关系:RemoteControl作为高层模块,不直接依赖具体的命令类(如LightOnCommand),而是依赖抽象的Command接口。这样,当具体命令类发生变化时,RemoteControl类不受影响。
    • 具体命令类与接收者的关系:具体命令类依赖于接收者的抽象(虽然这里接收者没有显式的抽象,但可以理解为依赖接收者的操作接口),而不是具体的接收者实现细节。例如,LightOnCommand只关心Light类有turnOn方法,而不关心Light类内部具体如何实现开启灯光的操作。

迪米特法则(Law of Demeter)

  • 解释:一个对象应该对其他对象有最少的了解,即一个类应该尽量减少与其他类之间的交互,只与直接的朋友通信。
  • 具体体现
    • 调用者与接收者的隔离:RemoteControl作为调用者,它只与Command对象交互,不需要了解接收者(如Light、AirConditioner)的具体实现。通过命令对象作为中间层,降低了调用者与接收者之间的耦合度。
    • 具体命令类的独立性:具体命令类(如LightOnCommand)只与它的直接朋友(Light接收者和Command接口)进行交互,不与其他无关的类产生不必要的联系。

命令模式的优缺点

优点

1. 解耦请求发送者和接收者
  • 发送者(如调用者类)不需要知道接收者(如具体执行操作的对象)是谁,也不需要了解接收者的具体实现细节。发送者只需要通过命令对象来间接执行操作,降低了系统的耦合度。例如在智能家居系统中,遥控器(发送者)不需要知道灯具(接收者)的具体电路和控制方式,只需要触发相应的命令对象即可。
2. 可扩展性强
  • 方便添加新的命令,只需要创建新的具体命令类并实现命令接口即可,不会影响到现有的其他类和模块。当系统需要新增功能时,如在智能家居系统中增加调节窗帘开合的功能,只需创建新的命令类和对应的接收者类,而无需修改遥控器(调用者)的代码。
3. 支持命令的撤销和重做
  • 可以在命令对象中记录命令执行前的状态,在需要撤销时恢复到之前的状态,重做时再次执行命令。这在许多应用场景中非常有用,如文本编辑器中的撤销和重做操作,通过命令模式可以很方便地实现。
4. 便于实现命令队列和日志记录
  • 可以将命令对象放入队列中,按照顺序依次执行,实现命令的排队执行。同时,也可以方便地记录命令的执行日志,便于系统的监控和故障排查。例如在多任务处理系统中,可以将一系列命令放入队列中,按顺序依次处理。
5. 符合开闭原则
  • 对扩展开放,对修改关闭。当需要增加新的命令时,只需要扩展新的具体命令类,而不需要修改现有的调用者和其他命令类,提高了系统的可维护性。

缺点

1. 类的数量增加
  • 每个具体的命令都需要创建一个对应的具体命令类,当系统中的命令较多时,会导致类的数量急剧增加,增加了系统的复杂性和维护成本。例如在一个复杂的游戏系统中,各种不同的操作都需要封装成命令类,可能会产生大量的类文件。
2. 命令过多时管理复杂
  • 如果系统中有大量的命令,管理这些命令对象会变得困难。需要有良好的组织和管理机制,否则会导致代码混乱,降低代码的可读性和可维护性。
3. 增加系统的理解难度
  • 由于引入了命令对象、调用者、接收者等多个角色和层次,对于不熟悉命令模式的开发者来说,理解和掌握系统的整体架构和工作流程会有一定的难度。
4. 性能开销
  • 每个命令都封装成一个对象,会带来一定的内存开销和对象创建、销毁的性能开销。特别是在对性能要求较高的系统中,这种开销可能会成为一个问题。

注意事项

设计层面

  1. 合理设计命令接口
    • 命令接口应简洁且具有通用性,只包含必要的方法,如execute()和undo()。过多的方法会增加具体命令类的实现复杂度,破坏单一职责原则。
    • 接口的命名要清晰,能准确表达命令的基本操作,方便其他开发者理解和使用。
  2. 控制类的数量
    • 命令模式可能会导致类的数量增多,尤其是在系统功能复杂、命令多样的情况下。要合理规划命令类的层次结构,避免类的泛滥。可以通过抽象命令类或命令组来减少重复代码和类的数量。
    • 例如,对于具有相似操作的命令,可以抽象出一个基类,让具体命令类继承该基类,复用公共的代码逻辑。
  3. 遵循设计原则
    • 严格遵循单一职责原则,确保每个类和接口只负责单一的功能。例如,具体命令类只负责封装特定的操作,接收者类只负责执行具体的业务逻辑。
    • 遵循开闭原则,在需要扩展新命令时,通过创建新的具体命令类来实现,而不是修改现有的代码。这样可以提高系统的可维护性和扩展性。

实现层面

  1. 内存管理
    • 由于命令模式会创建大量的命令对象,要注意内存的使用情况。特别是在命令频繁执行和撤销的场景下,可能会产生大量的临时对象,导致内存占用过高。
    • 可以考虑使用对象池技术来复用命令对象,减少对象的创建和销毁开销,提高系统的性能。
  2. 命令撤销和重做的实现
    • 如果需要支持命令的撤销和重做功能,要确保在命令对象中正确记录执行前的状态。在实现undo()方法时,要保证能准确地恢复到执行命令之前的状态。
    • 同时,要处理好撤销和重做操作的顺序和边界条件,避免出现状态不一致的问题。
  3. 线程安全
    • 在多线程环境下使用命令模式时,要考虑线程安全问题。如果多个线程同时操作命令队列或命令对象,可能会导致数据不一致或其他并发问题。
    • 可以通过同步机制(如synchronized关键字或Lock接口)来保证线程安全,或者使用线程安全的数据结构来存储命令。

使用场景层面

  1. 适用场景判断
    • 命令模式适用于需要将请求的发送者和接收者解耦、支持命令的撤销和重做、实现命令队列和日志记录等场景。在使用前要仔细分析系统需求,判断是否真正适合使用命令模式。
    • 如果系统的功能简单,请求和执行逻辑紧密耦合,使用命令模式可能会增加系统的复杂度,得不偿失。
  2. 与其他模式结合使用
    • 在实际开发中,命令模式可以与其他设计模式结合使用,以更好地满足系统需求。例如,与观察者模式结合,当命令执行完成后通知相关的观察者;与组合模式结合,实现命令的组合和嵌套执行。
    • 但在结合使用时,要注意不同模式之间的协调和兼容性,避免引入新的问题。

应用场景

1. 图形用户界面(GUI)应用程序

  • 按钮和菜单操作:在各种桌面应用程序、Web 应用程序或移动应用程序的图形用户界面中,用户通过点击按钮、选择菜单项等操作来触发各种功能。每个操作都可以封装成一个命令对象。例如,在文本编辑器中,“保存”“复制”“粘贴” 等操作对应的按钮点击事件可以分别封装成SaveCommand、CopyCommand、PasteCommand等命令对象。这样,GUI 组件(如按钮)作为调用者,只需要调用命令对象的execute()方法,而不需要关心具体的操作是如何实现的。
  • 撤销和重做功能:命令模式天然支持撤销和重做操作。在 GUI 应用中,这是一个非常常见且重要的功能。比如在图像编辑软件中,用户进行的每一步操作(如裁剪、调色、添加滤镜等)都可以封装成命令对象。当用户点击 “撤销” 按钮时,系统可以依次调用已执行命令对象的undo()方法,将图像恢复到之前的状态;点击 “重做” 按钮时,则可以再次调用这些命令对象的execute()方法。

2. 游戏开发

  • 游戏操作控制:游戏中的角色移动、攻击、释放技能等操作都可以使用命令模式来实现。例如,在一个角色扮演游戏中,玩家按下键盘上的某个按键来控制角色向前移动,这个操作可以封装成MoveForwardCommand命令对象。游戏控制器作为调用者,根据玩家的输入调用相应命令对象的execute()方法。这样可以方便地实现游戏操作的自定义和扩展,例如可以通过修改命令对象来改变角色的移动速度或攻击方式。
  • 游戏回放和存档:命令模式可以记录游戏中的所有操作,这些操作记录可以用于游戏回放。同时,也可以将这些命令序列保存到文件中,实现游戏存档功能。当玩家加载存档时,系统可以依次执行这些命令,将游戏状态恢复到存档时的状态。

3. 工作流系统

  • 任务调度和执行:在工作流系统中,每个任务的执行可以看作是一个命令。例如,在一个项目管理系统中,任务的分配、审批、完成等操作都可以封装成不同的命令对象。工作流引擎作为调用者,根据工作流的规则依次调用这些命令对象的execute()方法,完成任务的调度和执行。
  • 流程撤销和恢复:如果工作流中某个步骤出现错误或需要修改,命令模式的撤销和重做功能可以方便地实现流程的回退和恢复。例如,在一个审批流程中,如果审批人员误操作通过了一个不应该通过的申请,可以通过撤销相应的审批命令,将流程恢复到之前的状态。

4. 多线程和分布式系统

  • 任务队列和异步处理:在多线程或分布式系统中,命令模式可以用于实现任务队列和异步处理。将需要执行的任务封装成命令对象,放入任务队列中,多个工作线程或分布式节点从队列中取出命令对象并执行。这样可以实现任务的解耦和异步执行,提高系统的并发性能和可扩展性。
  • 日志记录和故障恢复:在分布式系统中,命令模式可以方便地记录每个操作的日志。当系统出现故障时,可以根据日志中的命令序列进行故障恢复。例如,在一个分布式数据库系统中,对数据库的增删改操作可以封装成命令对象,记录操作日志。当数据库节点出现故障重启时,可以根据日志中的命令对象重新执行操作,保证数据的一致性。

5. 智能家居系统

  • 设备控制:智能家居系统中,用户可以通过手机 APP 或智能遥控器来控制各种智能设备,如灯光、空调、窗帘等。每个设备的操作(如开灯、调节温度、打开窗帘等)都可以封装成命令对象。智能控制中心作为调用者,根据用户的指令调用相应命令对象的execute()方法,实现对设备的远程控制。
  • 场景模式设置:智能家居系统通常支持场景模式,如 “回家模式”“睡眠模式” 等。每个场景模式可以看作是一组命令的集合。例如,“回家模式” 可以包含打开灯光、打开空调、拉开窗帘等命令。当用户选择某个场景模式时,系统依次执行该场景模式下的所有命令对象。
【并发编程五】c++进程通信——共享内存(shared memmory) 现代操作系统,对于内存管理,采⽤的是虚拟内存技术,也就是每个进程都有⾃⼰独⽴的虚拟内存空间,不同进程的虚拟内存映射到不同的物理内存中。所以,即使进程 A中 和 进程 B中 的虚拟地址是⼀样的,其实访问的是不同的物理内存地址,对于数据的增删查改互不影响。这样这个进程写⼊的东⻄,另外⼀个进程⻢上就能看到了,都不需要拷⻉来拷⻉去,传来传去,⼤⼤提⾼了进程间通信的速度。⽤了共享内存通信⽅式,带来新的问题,那就是如果多个进程同时修改同⼀个共享内存,很有可能就冲突了。那共享内存的⽅式,就很好的解决了这⼀问题。 阅读详情

相关推荐

摄像头读取出现VIDIOC_STREAMON: No space left on device 错误

先说下原因,linux中为usb camera提供了一个标准的V4L2的驱动以方便使用,只要符合驱动规范就可以实现即插即用usb camera设备,即免驱动安装。 但市面上的USB 摄像头都是2.0的。usb bus的 bandwidth是有限的,而V4L2驱动采用的是贪心原则,即camera会要求获取最大带宽;因此将两个camera接入一路usb bus,打开第二个camera(尤其是采用YUV...

houge101的博客 9289

设计模式(行为型模式)之:命令模式(Command Pattern)

命令模式是一个高内聚的模式,其定义为:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请 求排队或者记录请求日志,可以提供命令的撤销和恢复功能。Receiver接受者角色:该角色就是干活的角色,命令传递到这里是应该被执行的Command命令角色:需要执行的所有命令都在这里声明Invoker调用者角色:接收到命令,并执行命令命令模式的意图是将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。

u013921164的博客 4581

车载与安防项目实战:如何用RK3588搭配NVP6158C实现4路AHD摄像头BT1120接入与同步预览

本文详细解析了基于RK3588处理器与NVP6158C解码芯片实现4路AHD摄像头BT1120接入与同步预览的技术方案。针对车载环视和安防监控场景,重点探讨了硬件架构设计、BT1120接口配置、多路同步机制及Android HAL适配等核心问题,提供了从底层驱动到上层应用的完整实现路径,为相关领域的工程实践提供可靠参考。

weixin_30571465的博客 486

JAVA设计模式--命令模式

目录 一、什么是命令式 二、命令模式的适用性 三、命令模式的结构 四、命令模式的优点 五、认识命令模式 六、总结 一、什么是命令式 命令(Command)模式又叫作动作(Action)模式或事务(Transaction)模式,是一种对象的行为模式。将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。 命令模式的本质:封...

pengjunlee的博客 5万+

解决银河麒麟V10分辨率问题:xrandr命令详解与常见错误排查

本文详细解析了在银河麒麟V10系统中使用xrandr命令调整屏幕分辨率的方法,包括核心功能解析、常见问题排查及持久化配置技巧。通过实战指南帮助用户解决分辨率缺失、配置失效等典型问题,提升多显示器环境下的工作效率。

weixin_30642561的博客 504

IP2315高效同步降压充电IC在快充应用中的硬件与软件控制策略

本文深入解析IP2315高效同步降压充电IC在快充应用中的硬件与软件控制策略,涵盖其核心特性、硬件电阻调节技巧、I2C动态控制方案、散热设计优化及典型问题排查。IP2315支持多种快充协议,如Type-C PD、华为FCP等,适用于便携设备快速充电需求,并通过I2C实现灵活的充电参数设置,提升充电效率与安全性。

weixin_29248313的博客 539

设计模式第19讲——命令模式(Command)

命令模式(Command Pattern)是一种行为型设计模式,又叫动作模式或事务模式。一、什么是命令模式 二、角色组成 三、优缺点 四、应用场景 4.1 生活场景4.2 java场景五、代码实现5.0 UML类图 5.1 抽象命令(Command)——Command5.2接收者(Receiver)——Chef5.3具体命令(Concrete Command)——OrderCommand六、总结

让~学习~成为一种习惯(橡 皮 人の技术博客) 1万+

Google Earth Engine——使用STARFM 图像融合算法将Landsat 和 MODIS 融合得出2000-2023 NDVI长时序图(空间分辨率为 30 米、时间分辨率为 16 天)

非本地入侵物种是全球生态系统面临的主要威胁之一。野葛(Pueraria montana)是一种生长迅速的藤本植物,原产于亚洲,现已入侵美国一些地区,因此该物种的管理成为一个重要问题。利用 Landsat 和 MODIS 平台收集的数据,计算了 2000 年至 2015 年肯塔基州三个侵扰地点的归一化差异植被指数(NDVI)估算值。使用 STARFM 图像融合算法将大地遥感卫星和 MODIS 得出的 NDVI 结合成空间分辨率为 30 米、时间分辨率为 16 天的时间序列。

此星光明博客 2509

设计模式-命令模式(Command)

命令模式是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。命令模式的主要优点是可以将请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。主要解决在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。

miaoyl的博客 2945

基于百度地图API在AI Studio上的卫星地图块图像处理与分类

本项目基于百度地图API获取了不同的瓦片地图并进行合并等处理,可用于遥感和抽象地图的地图块的图像分类、分割、检测等数据的制作。瓦片地图金字塔模型是一种多分辨率层次模型,从瓦片金字塔的底层到顶层,分辨率越来越低,但表示的地理范围不变。首先确定地图服务平台所要提供的缩放级别的数量N,把缩放级别最高、地图比例尺最大的地图图片作为金字塔的底层,即第0层,并对其进行分块,从地图图片的左上角开始,从左至右、从上到下进行切割,分割成相同大小(比如256x256像素)的正方形地图瓦片,形成第0层瓦片矩阵;

斌擎科技 746

6、核函数与再生核希尔伯特空间:原理、应用与实践

本文系统介绍了核函数与再生核希尔伯特空间(RKHS)的理论基础、核心性质及其在机器学习和信号处理中的广泛应用。文章从核方法的优势出发,阐述了其在非线性建模、正则化和算法核化方面的独特价值,并深入探讨了正定核、Mercer定理、表示定理等关键理论。通过构建多种标准核与工程专用核,展示了核函数的设计灵活性。结合支持向量回归(SVR)模型与多个MATLAB示例,详细说明了核方法的实际应用流程与操作技巧。最后,总结了核方法的应用领域、未来发展方向及学习实践建议,为读者提供了一套完整的理论与实践指南。

z2a3b4c5d的博客 143

设计模式之【命令模式】,方法调用的花式玩法

命令模式(Command Pattern)是对命令的封装,每一个命令都是一个操作:请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行操作。命令模式解耦了请求方和接收方,请求方只需请求执行命令,不用关心命令是怎样被接受,怎样被操作以及是否被执行等。命令模式属于行为型模式。原文:将一个请求封装成医德对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。在软件系统中,行为请求者与行为实现者通常是一种紧耦合关系,因为这样的实现简单明了。

秃了也弱了 3751

卸载python弹框报错:Could not set file security for file ‘D:\Config.Msi\abd5.rbf‘. Error: 5. Verify...如何解决?

🏆本文收录于 《全栈 Bug 调优(实战版)》 专栏。专栏聚焦真实项目中的各类疑难 Bug,从成因剖析 → 排查路径 → 解决方案 → 预防优化全链路拆解,形成一套可复用、可沉淀的实战知识体系。无论你是初入职场的开发者,还是负责复杂项目的资深工程师,都可以在这里构建一套属于自己的「问题诊断与性能调优」方法论,助你稳步进阶、放大技术价值 。

**My Coding Family** 6485

23种设计模式之命令模式(Command Pattern)

大家好,我是小威,24届毕业生,在一家满意的公司实习。命令模式,此篇文章为一天学习一个设计模式系列文章,后面会分享其他模式知识。

小威的博客 2万+

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

二十三种设计模式——命令模式(Command Pattern)

命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。 介绍 意图:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。 主要解决:在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为...

也曾北风温柔以待 301

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

您的设计模式——命令模式【Command Pattern 】

今天讲命令模式,这个模式从名字上看就很简单,命令嘛,老大发命令,小兵执行就是了,确实是这个意思, 但是更深化了,用模式来描述真是是世界的命令情况。正在看这本书的你,我猜测分为两类:已经工作的和没有 工作的,先说没有工作的,那你为啥要看这本书,为了以后工作呗,只要你参加工作,你肯定会待在项目组,那 今天我们就以项目组为例子来讲述命令模式。 我是我们部门的项目经理,就是一个项目的头,在中国做项目

418

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

设计模式-命令模式-Command Pattern

创建一个命令接口,它包含执行操作的方法(如。

wesigj的博客 2031

【设计模式】命令模式(Command Pattern) 服务我要个火锅ru

目录 一.介绍 二.场景 三.实现 四.dome代码 一.介绍 命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。 意图:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。 主要解决:在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这.

corleone_4ever的博客 270

秒懂设计模式之命令模式(Command Pattern)

[版权申明] 非商业目的注明出处可自由转载 博文地址:https://blog.youkuaiyun.com/ShuSheng0007/article/details/116035276 出自:shusheng007 设计模式汇总篇,一定要收藏: 永不磨灭的设计模式(有这一篇真够了,拒绝标题党) 文章目录概述类型难度定义使用场景UML实例第一步:声明一个命令接口 (Command)第二步:构建那些可以具体完成命令的角色(Receiver)第三步:构建各种具体命令(ConcreteCommand)第四步:构建命令的调.

ShuSheng007的程序人生 3321

设计模式教程:命令模式(Command Pattern)

将请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化,将请求排队或记录日志,以及支持撤销操作

遇见伯灵说的博客 2035

设计模式命令模式(CommandPattern)

核心模块:抽象命令类、具体命令类、命令接收者、调用者 所有代码请访问:git@code.aliyun.com:289804201/PatternLearn.git 使用场景:不知道请求的接收者,不知道请求的操作,主要封装不同的命令,可以使用这种松耦合的方式; 优点:低耦合度,新的命令很容易添加到系统,支持undo和redo操作,和命令队列; 缺点:如果命令过多导

didiao11300的专栏 268

23种设计模式——命令模式(Command Pattern)

本文介绍了23种经典设计模式之——命令模式(Command Pattern)的使用及说明

Meteors.的博客 688

设计模式 命令模式(Command Pattern)

每个命令对象都可以记录其执行前后的状态,这样在需要撤销操作时可以恢复到之前的状态。例如,当用户点击一个按钮或选择一个菜单项时,可以创建一个命令对象来表示这个请求,然后在适当的时候执行该命令。可以将多个简单的命令组合成一个复合命令,这样就可以一次执行一系列操作。命令模式(Command Pattern)是一种行为设计模式,它把请求封装成对象,从而让你可以用不同的请求、队列或者日志来参数化其他对象。这个示例展示了命令模式的基本应用,通过将请求封装成对象,使得发送请求的对象和执行请求的对象之间松耦合。

ling_zhi_xin的博客 1586

设计模式-命令模式

命令模式 命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。 模式结构 command:定义命令的接口,声明执行的方法。 concretecommand:命令接口实现对象,是“虚”的实现,永昌汇持有接收者,并调用接受者的功能来完...

小码农一枚 266

设计模式(十五)——命令模式(Command Pattern)

命令模式(Command Pattern) 基本介绍 命令模式:将一一个请求封装为一一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。也称之为:动作Action模式、事务transaction模式。 命名模式使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活,实现解耦。 在命名模式中,会将一个请求封装为一个对象,以便使用...

Duktig的博客 369

Java设计模式——命令模式【Command Pattern】

Java设计模式、命令模式、Command Pattern

scorpio的博客 1039
上一篇: 设计模式之责任链模式
下一篇: 设计模式之解释器模式
LiaoYuan.Dai
博客等级 码龄7年 247粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值