网站专业制作公司,安徽省城乡和住房建设厅网站,福建网站开发招聘,化妆品商城网站建设策划方案命令模式#xff08;Command Pattern#xff09;详解一、命令模式简介
命令模式#xff08;Command Pattern#xff09; 是一种 行为型设计模式#xff08;对象行为型模式#xff09;#xff0c;它将一个请求封装为一个对象#xff0c;从而使你可以用不同的请求对客户进…命令模式Command Pattern详解一、命令模式简介
命令模式Command Pattern 是一种 行为型设计模式对象行为型模式它将一个请求封装为一个对象从而使你可以用不同的请求对客户进行参数化并支持请求的排队、记录日志、撤销等操作。
别名为动作(Action)模式或事务(Transaction)模式
简单来说“把一次方法调用包装成一个对象这样你就可以像处理普通对象一样来处理这些请求。”将请求发送者和接收者完全解耦
发送者与接收者之间没有直接引用关系
发送请求的对象只需要知道如何发送请求而不必知道如何完成请求相同的开关可以通过不同的电线来控制不同的电器
开关 - - 请求发送者
电灯- - 请求的最终接收者和处理者
开关和电灯之间并不存在直接耦合关系它们通过电线连接在一起使用不同的电线可以连接不同的请求接收者命令模式包含以下4个角色
Command抽象命令类
ConcreteCommand具体命令类
Invoker调用者
Receiver接收者命令模式的本质是对请求进行封装。
一个请求对应于一个命令将发出命令的责任和执行命令的责任分开。
命令模式允许请求的一方和接收的一方独立开来使得请求的一方不必知道接收请求的一方的接口更不必知道请求如何被接收、操作是否被执行、何时被执行以及是怎么被执行的。二、解决的问题类型
命令模式主要用于解决以下问题
解耦请求发送者和接收者发送者不需要知道具体执行逻辑只需要知道如何发送“命令”。支持撤销/重做功能通过保存命令历史可以轻松实现撤销或重做操作。支持事务回滚、日志记录、队列任务等功能命令可以被记录、排队、延迟执行。在不同的时间指定请求、将请求排队和执行请求系统需要将一组操作组合在一起形成宏命令三、使用场景场景示例支持撤销操作文本编辑器中的“撤销”、“重做”按钮解耦调用方与执行方遥控器控制多个家电设备实现宏命令执行一组命令的组合操作任务队列将多个命令加入队列异步执行日志与恢复记录命令执行日志系统崩溃后可恢复
四、核心角色角色描述Command命令接口定义执行命令的方法如 execute()ConcreteCommand具体命令实现 Command 接口绑定具体的接收者Receiver并调用其方法Invoker调用者持有命令对象负责调用命令的 execute() 方法Receiver接收者实际执行命令的对象包含业务逻辑Client客户端创建命令对象并设置接收者将命令交给调用者执行
五、代码案例Java
我们以“智能遥控器控制家电”为例来演示命令模式的使用。
1. 定义命令接口
// 命令接口
interface Command {void execute();void undo(); // 可选用于撤销操作
}2. 创建接收者类实际执行动作的对象
// 灯的接收者
class Light {public void on() {System.out.println(The light is ON);}public void off() {System.out.println(The light is OFF);}
}// 风扇的接收者
class Fan {public void start() {System.out.println(The fan is STARTING);}public void stop() {System.out.println(The fan is STOPPING);}
}3. 创建具体命令类
// 开灯命令
class LightOnCommand implements Command {private Light light;public LightOnCommand(Light light) {this.light light;}Overridepublic void execute() {light.on();}Overridepublic void undo() {light.off();}
}// 关风扇命令
class FanOffCommand implements Command {private Fan fan;public FanOffCommand(Fan fan) {this.fan fan;}Overridepublic void execute() {fan.stop();}Overridepublic void undo() {fan.start();}
}4. 创建调用者比如遥控器
// 遥控器
class RemoteControl {private Command command;public void setCommand(Command command) {this.command command;}public void pressButton() {command.execute();}public void pressUndo() {command.undo();}
}5. 客户端测试代码
public class Client {public static void main(String[] args) {// 创建接收者Light light new Light();Fan fan new Fan();// 创建具体命令Command lightOn new LightOnCommand(light);Command fanOff new FanOffCommand(fan);// 创建调用者RemoteControl remote new RemoteControl();// 设置命令并执行remote.setCommand(lightOn);remote.pressButton(); // 输出The light is ONremote.pressUndo(); // 输出The light is OFFSystem.out.println(----------);remote.setCommand(fanOff);remote.pressButton(); // 输出The fan is STOPPINGremote.pressUndo(); // 输出The fan is STARTING}
}典型代码C
典型的抽象命令类代码
abstract class Command
{public abstract void Execute();
}典型的调用者请求发送者类代码
class Invoker
{private Command command;//构造注入public Invoker(Command command){this.commandcommand;} public Command Command{get { return command; }//设值注入set { command value; }
} //业务方法用于调用命令类的方法public void Call(){command.Execute();}
}典型的具体命令类代码
class ConcreteCommand : Command
{private Receiver receiver; //维持一个对请求接收者对象的引用public override void Execute(){receiver.Action();//调用请求接收者的业务处理方法Action()}
}典型的请求接收者类代码
class Receiver
{public void Action(){//具体操作}
}其他案例C
为了用户使用方便某系统提供了一系列功能键用户可以自定义功能键的功能例如功能键FunctionButton可以用于退出系统由SystemExitClass类来实现也可以用于显示帮助文档由DisplayHelpClass类来实现。
用户可以通过修改配置文件来改变功能键的用途现使用命令模式来设计该系统使得功能键类与功能类之间解耦可为同一个功能键设置不同的功能。电视机遥控器
电视机是请求的接收者遥控器是请求的发送者遥控器上有一些按钮不同的按钮对应电视机的不同操作。抽象命令角色由一个命令接口来扮演有三个具体的命令类实现了抽象命令接口这三个具体命令类分别代表三种操作打开电视机、关闭电视机和切换频道。显然电视机遥控器就是一个典型的命令模式应用实例。六、优缺点分析优点描述✅ 解耦调用者与接收者调用者无需了解具体执行细节只需调用命令即可✅ 支持撤销/重做、宏命令、日志记录等高级功能通过命令对象可以轻松实现这些功能可以比较容易地设计一个命令队列或宏命令组合命令为请求的撤销(Undo)和恢复(Redo)操作提供了一种设计和实现方案✅ 扩展性好新增命令只需添加新的 ConcreteCommand 类符合开闭原则
缺点描述❌ 增加类的数量每个命令都需要一个类可能造成类爆炸❌ 理解成本高对于新手来说结构略复杂需要一定学习成本❌ 性能开销如果频繁创建命令对象可能带来额外内存消耗
七、与其他模式对比补充模式名称目标策略模式封装算法让算法可替换强调“行为切换”观察者模式当对象状态改变时通知所有监听者命令模式将请求封装成对象便于传递、存储、撤销等操作
八、最终小结
命令模式是一种非常灵活且强大的行为型设计模式它适用于
需要解耦请求发送者和接收者的场景需要支持撤销、重做、日志记录等高级功能需要构建任务队列、宏命令、批处理机制等系统功能。一句话总结命令模式就像“遥控器”你按下按钮背后谁在干活你不知道但你知道事情能办成。✅ 推荐使用方式
在需要撤销/重做的系统中优先考虑命令模式结合“命令历史”实现多级撤销使用“宏命令”批量执行多个命令用 JSON 序列化保存命令状态实现持久化。
九、扩展
实现命令队列
动机
当一个请求发送者发送一个请求时有不止一个请求接收者产生响应这些请求接收者将逐个执行业务方法完成对请求的处理。增加一个CommandQueue类由该类负责存储多个命令对象而不同的命令对象可以对应不同的请求接收者。批处理。
实现
using System.Collections.Generic;
namespace CommandSample
{class CommandQueue{//定义一个List来存储命令队列private ListCommand commands new ListCommand();public void AddCommand(Command command){commands.Add(command);}public void RemoveCommand(Command command){commands.Remove(command);}//循环调用每一个命令对象的Execute()方法public void Execute() {foreach (object command in commands) {((Command)command).Execute();}}}
}记录请求日志
动机
将请求的历史记录保存下来通常以日志文件(Log File)的形式永久存储在计算机中
为系统提供一种恢复机制可以用于实现批处理防止因为断电或者系统重启等原因造成请求丢失而且可以避免重新发送全部请求时造成某些命令的重复执行
实现
将发送请求的命令对象通过序列化写到日志文件中
命令类必须使用属性[Serializable]标记为可序列化实现撤销操作
实例
可以通过对命令类进行修改使得系统支持撤销(Undo)操作和恢复(Redo)操作。
设计一个简易计算器该计算器可以实现简单的数学运算还可以对运算实施撤销操作。宏命令
动机
宏命令(Macro Command)又称为组合命令(Composite Command)它是组合模式和命令模式联用的产物宏命令是一个具体命令类它拥有一个集合在该集合中包含了对其他命令对象的引用当调用宏命令的Execute()方法时将递归调用它所包含的每个成员命令的Execute()方法。一个宏命令的成员可以是简单命令还可以继续是宏命令执行一个宏命令将触发多个具体命令的执行从而实现对命令的批处理部分内容由AI大模型生成注意识别