Head First 设计模式 06-命令模式
命令模式 将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其它对象。命令模式也支持可撤销的操作。
书中分别列举了 遥控器 和 餐厅下单 两个例子。
我的理解是 命令模式 主要目的是为了解耦 触发任务的对象 和 实际执行的对象 ,即 调用者(Invoker
)和 接收者(Receiver
)。
类图如下:
下面是模拟在 Client 中执行的测试代码。
csharp
Invoker invoker = new Invoker(); // 调用者
Receiver receiver = new Receiver(); // 命令接收者
ConcreteCommand command = new ConcreteCommand(receiver); // 创建命令
invoker.SetCommand(command); // 设置命令
invoker.Execute(); // 执行
invoker.Undo(); // 撤销
1
2
3
4
5
6
2
3
4
5
6
示例代码
Command
csharp
interface Command
{
void Execute();
void Undo();
}
1
2
3
4
5
2
3
4
5
Receiver
csharp
class Receiver
{
public void Action()
{
Console.WriteLine("The receiver do an action.");
}
public void Undo()
{
Console.WriteLine("The receiver undo the action.");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
ConcreteCommand
csharp
class ConcreteCommand : Command
{
Receiver _receiver;
public ConcreteCommand(Receiver receiver)
{
_receiver = receiver;
}
public void Execute()
{
_receiver.Action();
}
public void Undo()
{
_receiver.Undo();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Invoker
csharp
class Invoker
{
Command _command;
public void SetCommand(Command command)
{
_command = command;
}
public void Execute()
{
_command.Execute();
}
public void Undo()
{
_command.Undo();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Client
csharp
class Client
{
static void Main(string[] args)
{
Invoker invoker = new Invoker(); // 调用者
Receiver receiver = new Receiver(); // 命令接收者
ConcreteCommand command = new ConcreteCommand(receiver); // 创建命令
invoker.SetCommand(command); // 设置命令
invoker.Execute(); // 执行
invoker.Undo(); // 撤销
Console.ReadLine();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
宏命令
可以将 Invoker 中的 Command 修改为列表,来实现一次执行多个命令,实现类似于 宏命令 的效果。
csharp
class BathInvoker
{
List<Command> _commands;
public void SetCommand(Command command)
{
_commands.Add(command);
}
public void Execute()
{
foreach (var command in _commands)
{
command.Execute();
}
}
public void Undo()
{
foreach (var command in _commands)
{
command.Undo();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
更多用途
队列请求
在宏命令的基础上,基于队列和实际的执行者之间是完全解耦的,可以实现类似于队列和消费的效果。
日志请求
类似于 SQLServer 的日志,可以根据日志恢复数据库曾经执行过的操作。
使用命令模式可以实现类似的效果,只需要追加Store()
和Load()
方法。