命令者模式是一个高内聚的模式, 其定义为: Encapsulate a request as an object,thereby letting you parameterize clients with different requests,queue or log requests,and support undoable operations.(将一个请求封装成一个对象, 从而让你使用不同的请求把客户端参数化, 对请求排队或者记录请求日志, 可以提供命令的撤销和恢复功能。 )
UML图:
代码实现:
#include <stdio.h>
#include <stdlib.h>// 命令接口
typedef struct {void (*execute)(void*);void (*undo)(void*);
} Command;// 具体命令类
typedef struct {Command command;void* receiver;void (*action)(void*);void (*undoAction)(void*);
} ConcreteCommand;void ConcreteCommand_execute(void* obj) {ConcreteCommand* self = (ConcreteCommand*)obj;self->action(self->receiver);
}void ConcreteCommand_undo(void* obj) {ConcreteCommand* self = (ConcreteCommand*)obj;self->undoAction(self->receiver);
}ConcreteCommand createConcreteCommand(void* receiver, void (*action)(void*), void (*undoAction)(void*)) {ConcreteCommand command;command.command.execute = ConcreteCommand_execute;command.command.undo = ConcreteCommand_undo;command.receiver = receiver;command.action = action;command.undoAction = undoAction;return command;
}// 调用者类
typedef struct {Command* command;void (*setCommand)(void*, Command*);void (*executeCommand)(void*);void (*undoCommand)(void*);
} Invoker;void Invoker_setCommand(void* obj, Command* command) {Invoker* self = (Invoker*)obj;self->command = command;
}void Invoker_executeCommand(void* obj) {Invoker* self = (Invoker*)obj;self->command->execute(self->command);
}void Invoker_undoCommand(void* obj) {Invoker* self = (Invoker*)obj;self->command->undo(self->command);
}Invoker createInvoker() {Invoker invoker;invoker.setCommand = Invoker_setCommand;invoker.executeCommand = Invoker_executeCommand;invoker.undoCommand = Invoker_undoCommand;return invoker;
}// 接收者类
typedef struct {void (*action)(void*);void (*undoAction)(void*);
} Receiver;void Receiver_action(void* obj) {printf("Receiver performs action.\n");
}void Receiver_undoAction(void* obj) {printf("Receiver undoes action.\n");
}Receiver createReceiver() {Receiver receiver;receiver.action = Receiver_action;receiver.undoAction = Receiver_undoAction;return receiver;
}int main() {Receiver receiver = createReceiver();ConcreteCommand command = createConcreteCommand(&receiver, &receiver.action, &receiver.undoAction);Invoker invoker = createInvoker();invoker.setCommand(&invoker, &command);invoker.executeCommand(&invoker);invoker.undoCommand(&invoker);return 0;
}
在上面的示例代码中,定义了命令接口Command
和具体命令类ConcreteCommand
,实现了执行和撤销方法来处理具体的命令。
同时还定义了调用者类Invoker
,具有设置命令、执行命令和撤销命令的方法,并通过命令对象来调用相应的方法。
还定义了接收者类Receiver
,具有执行操作和撤销操作的方法。
在main
函数中,首先创建了一个接收者对象receiver
,然后创建了一个具体命令对象command
,并将接收者对象和相应的操作方法传入。
接着创建了一个调用者对象invoker
,通过调用者对象设置命令对象,并执行和撤销命令。
命令模式的优点:
-
可以将请求发送者与接收者解耦,使得请求发送者不需要知道具体的接收者和处理方法。
-
可以实现请求的参数化、队列化和记录日志等功能。
-
支持可撤销操作,可以随时撤销执行过的命令。
命令模式的缺点:
-
可能导致命令类的数量增加,因为每个具体命令都需要实现一个命令类。
-
可能引入额外的开销,因为需要维护命令对象和命令队列。
适用场景:
-
需要将请求发送者和接收者解耦的场景。
-
需要支持请求的参数化、队列化和记录日志等功能的场景。
-
需要支持可撤销操作的场景。
总结:命令模式通过将请求封装成对象来实现请求的参数化、队列化和记录日志等功能,并且支持可撤销操作。它可以降低系统的耦合度,提高系统的灵活性和可维护性。