命令者模式是一个高内聚的模式, 其定义为: 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
,通过调用者对象设置命令对象,并执行和撤销命令。
命令模式的优点:
-
可以将请求发送者与接收者解耦,使得请求发送者不需要知道具体的接收者和处理方法。
-
可以实现请求的参数化、队列化和记录日志等功能。
-
支持可撤销操作,可以随时撤销执行过的命令。
命令模式的缺点:
-
可能导致命令类的数量增加,因为每个具体命令都需要实现一个命令类。
-
可能引入额外的开销,因为需要维护命令对象和命令队列。
适用场景:
-
需要将请求发送者和接收者解耦的场景。
-
需要支持请求的参数化、队列化和记录日志等功能的场景。
-
需要支持可撤销操作的场景。
总结:命令模式通过将请求封装成对象来实现请求的参数化、队列化和记录日志等功能,并且支持可撤销操作。它可以降低系统的耦合度,提高系统的灵活性和可维护性。