命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
命令模式可通过“命令对象”将“动作的请求者”从“动作的执行者”对象中解耦。一个命令对象通过在特定接收者上绑定一组动作来封装一个请求。要达到这一点,命令对象需要将动作和接收者封装进对象中。
也可以创建命令的宏,以便一次执行多个命令。
优点:
- 就是将行为请求者和行为实现者解耦,降低了系统耦合度
- 便于扩展新的命令,以及使用命令组合
缺点:
- 使用命令模式可能会导致某些系统有过多的具体命令类,增加了系统的复杂性
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 27
| /// 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 67 68
| /// 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 26
| // 创建电视 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 11
| TV - 开机 当前收看频道: 1 当前收看频道: 3 当前收看频道: 9 当前音量: 11 当前音量: 12 当前音量: 13 当前音量: 12 当前音量: 13 TV - 关机
|