由于最近一直在学习Golang,所以从本节起,所有设计模式学习笔记中的源码都由Golang来完成~
命令模式:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
仔细看这个定义,我们知道一个命令对象通过在特定接收者(receiver)上绑定一组动作来封装一个请求。要达到这一点,命令对象将动作和接收者包进对象中。这个对象只暴露出一个execute()方法,当此方法被调用的时候,接收者就会进行这些动作。从外面看,其他对象不知道究竟哪个接收者进行了哪些动作,只知道如果调用了execute(),请求的目的就达到了。这些就实现了接收者和调用者的解耦合。
实现命令接口:
首先让所有的命令对象实现相同的包含一个方法的接口:
type command interface { execute() } //开灯命令 type lightOnCommand struct { mLight *light //命令对象包含的特定接收者 } //返回一个开灯命令的实例对象 func NewLightOnCommand(light *light) command { return &lightOnCommand{mLight: light} } //实现接口方法捆绑接收者的动作 func (this *lightOnCommand) execute() { if !this.mLight.isOn() { this.mLight.setOn(true) //开灯 } } //关灯命令 type lightOffCommand struct { mLight *light } func NewLightOffCommand(light *light) command { return &lightOffCommand{mLight: light} } func (this *lightOffCommand) execute() { if this.mLight.isOn() { this.mLight.setOn(false) //关灯 } }
我们应当考虑面向接口编程,大部分接收者都有简单的开关命令,故上述的代码可改为:
type receiver interface { setOn(bool) //true:开/false:关 isOn() bool } //打开命令 type onCommand struct { receiver Receiver } //创建打开命令的实例,为该实例捆绑接收者 func NewOnCommand(receiver Receiver) command { return &onCommand{receiver} } //被封装的“请求” func (this *onCommand) execute() { if !this.receiver.isOn() { this.receiver.setOn(true) //打开 } } //关闭命令 type offCommand struct { receiver Receiver } func NewOffCommand(receiver Receiver) command { return &offCommand{receiver} } func (this *offCommand) execute() { if !this.receiver.isOn() { this.receiver.setOn(false) //关闭 } }
最后,再来看看客户端的代码:
type RemoteController struct { slot command } func (this *RemoteController) SetCommand(command command) { this.slot = command } func (this *RemoteController) ButtonPressed() { if this.slot == nil { panic("Do not assign command to Controller's slot!") } this.slot.execute() }
看看接收者们:
const ( LIGHT = " light" DOOR = " door" ) //接收者接口 type Receiver interface { setOn(bool) isOn() bool } type light struct { name string on bool } func (this *light) setOn(b bool) { if b { fmt.Println(this.name + LIGHT + " is on.") } else { fmt.Println(this.name + LIGHT + " is off.") } this.on = b } func (this *light) isOn() bool { return this.on } func NewRoomLight() Receiver { return &light{"Room",false} } func NewTableLampLight() Receiver { return &light{"Table Lamp",false} } type door struct { name string on bool } func (this *door) setOn(b bool) { if b { fmt.Println(this.name + DOOR + " is opened.") } else { fmt.Println(this.name + DOOR + " is closed.") } this.on = b } func (this *door) isOn() bool { return this.on } func NewGarageDoor() Receiver { return &door{"Garage",false} } func NewKitchenDoor() Receiver { return &door{"Kitchen",false} }
来测试下吧~:
func main() { ctrl := new(command.RemoteController) var roomLight,garageDoor command.Receiver roomLight = command.NewRoomLight() garageDoor = command.NewGarageDoor() cmdOn := command.NewOnCommand(roomLight) cmdOff := command.NewOffCommand(garageDoor) ctrl.SetCommand(cmdOn) ctrl.ButtonPressed() ctrl.SetCommand(cmdOff) ctrl.ButtonPressed() }