命令模式入门

命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。

命令模式可通过“命令对象”将“动作的请求者”从“动作的执行者”对象中解耦。一个命令对象通过在特定接收者上绑定一组动作来封装一个请求。要达到这一点,命令对象需要将动作和接收者封装进对象中。

也可以创建命令的宏,以便一次执行多个命令。

优点:

  • 就是将行为请求者和行为实现者解耦,降低了系统耦合度
  • 便于扩展新的命令,以及使用命令组合

缺点:

  • 使用命令模式可能会导致某些系统有过多的具体命令类,增加了系统的复杂性

UML类图

代码示例

1
2
3
4
5
一个简单的电视遥控器程序,包含:
0-9:十个数字按键
ON/OFF: 电视电源开关键
Volume: Add/Minus
Undo: 撤销最后一次操作

创建命令(Command):

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/// Command Pattern - Command
/// 频道选择
class channelCommand: Command {
var tv: AppleTV
var channelIndex = defaultChannel
var preChannelIndex = defaultChannel
init(tv:AppleTV, channelIndex: Int) {
self.channelIndex = channelIndex
self.tv = tv
}
func execute() {
//保存上一次的频道,以便于undo操作
self.preChannelIndex = self.tv.channelIndex
self.tv.channelIndex = self.channelIndex
}

func undo() {
self.tv.channelIndex = self.preChannelIndex
}
}

/// 开机
class TVOnCommand: Command {
var tv: AppleTV
init(tv:AppleTV) {
self.tv = tv
}
func execute() {
tv.updatePowerStatus(status: true)
}

func undo() {
tv.updatePowerStatus(status: false)
}
}

/// 关机
class TVOffCommand: Command {
var tv: AppleTV
init(tv:AppleTV) {
self.tv = tv
}
func execute() {
tv.updatePowerStatus(status: false)
}

func undo() {
tv.updatePowerStatus(status: true)
}
}


/// 音量增
class VolumeAddCommand: Command {
var tv: AppleTV
init(tv:AppleTV) {
self.tv = tv
}
func execute() {
tv.updateVolume(step: 1)
}

func undo() {
tv.updateVolume(step: -1)
}
}

/// 音量减
class VolumeMinusCommand: Command {
var tv: AppleTV
init(tv:AppleTV) {
self.tv = tv
}
func execute() {
tv.updateVolume(step: -1)
}

func undo() {
tv.updateVolume(step: 1)
}
}


class NoCommand: Command {
func execute() {
print("Nothing to execute")
}

func undo() {
print("Nothing to undo")
}
}

创建命令具体执行者(Reveiver):

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
26
/// Command Pattern - Reveiver
/// 模拟TV,用来接受遥控器信号
class AppleTV {

/// 音量
var volume: Int = 10

var channelIndex: Int = defaultChannel {
didSet{
print("当前收看频道: \(channelIndex)")
}
}

func updatePowerStatus(status:Bool) {
if status == true {
print("TV - 开机")
}else{
print("TV - 关机")
}
}

func updateVolume(step: Int) {
self.volume += step
print("当前音量: \(self.volume)")
}
}

创建命令调用者(Invoker):

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

/// Command Pattern - Invoker
class SimpleRemoteConrtrol {
var channelCommands = [Command]()
var tv: AppleTV
var volumeAddCommand: VolumeAddCommand
var volumeMinusCommand: VolumeMinusCommand
var powerOnCommand: TVOnCommand
var powerOffCommand: TVOffCommand
var lastCommand:Command = NoCommand()
var currentPowerStatus = false

init(tv: AppleTV) {
self.tv = tv
//绑定频道命令
for index in 0...9 {
let command = channelCommand(tv: tv, channelIndex: index)
channelCommands.append(command)
}
//绑定音量命令
volumeAddCommand = VolumeAddCommand(tv: tv)
volumeMinusCommand = VolumeMinusCommand(tv: tv)

//绑定电源命令
powerOnCommand = TVOnCommand(tv: tv)
powerOffCommand = TVOffCommand(tv: tv)
}


/// 模拟频道选择
func channelBtnOnClick(channel:Int) -> Void {
let command = self.channelCommands[channel]
command.execute()
lastCommand = command
}

/// 模拟按下电源键
func powerBtnOnClick() -> Void {
if currentPowerStatus == true {
powerOffCommand.execute()
currentPowerStatus = false
lastCommand = powerOffCommand

}else{
powerOnCommand.execute()
currentPowerStatus = true
lastCommand = powerOnCommand
}
}

/// 模拟按下音量增
func volumeAddBtnOnClick() -> Void {
volumeAddCommand.execute()
lastCommand = volumeAddCommand
}
/// 模拟按下音量减
func volumeMinusBtnOnClick() -> Void {
volumeMinusCommand.execute()
lastCommand = volumeMinusCommand
}

/// 模拟按下撤销按钮
func undoBtnOnClick() -> Void {
lastCommand.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
// 创建电视
let tv = AppleTV()

// 创建遥控器
let remoteControl = SimpleRemoteConrtrol(tv: tv)

// 开机
remoteControl.powerBtnOnClick()

// 换台
remoteControl.channelBtnOnClick(channel: 1)
remoteControl.channelBtnOnClick(channel: 3)
remoteControl.channelBtnOnClick(channel: 9)

// 音量调节
remoteControl.volumeAddBtnOnClick()
remoteControl.volumeAddBtnOnClick()
remoteControl.volumeAddBtnOnClick()
remoteControl.volumeMinusBtnOnClick()

// 撤销
remoteControl.undoBtnOnClick()

// 关机
remoteControl.powerBtnOnClick()

执行结果:

1
2
3
4
5
6
7
8
9
10
TV - 开机
当前收看频道: 1
当前收看频道: 3
当前收看频道: 9
当前音量: 11
当前音量: 12
当前音量: 13
当前音量: 12
当前音量: 13
TV - 关机