go语言设计模式之命令模式
命令模式
命令模式是将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为模式,其别名为动作模式或事务模式。
优点
- 一个调用者想创建一个对象,只知道对象名称就可以了;
- 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以;
- 屏蔽产品的具体实现,调用者只关心产品的接口;
命令模式中有如下几个角色
Command:命令
Invoker:调用者
Receiver:接受者
Client:客户端
它们的关系可以这么来描述:客户端通过调用者发送命令,命令调用接受者执行相应操作。
代码
//电视类
type TV struct {
}
func (p TV) Open() {
fmt.Println("Play...")
}
func (p TV) Close() {
fmt.Println("Stop...")
}
//遥控器上的按键
type Command interface {
Press()
}
type OpenCommand struct {
tv TV
}
func (p OpenCommand) Press() {
p.tv.Open()
}
type CloseCommand struct {
tv TV
}
func (p CloseCommand) Press() {
p.tv.Close()
}
//调用者(遥控器)
type Invoker struct {
cmd Command
}
func (p *Invoker) SetCommand(cmd Command) {
p.cmd = cmd
}
func (p *Invoker) Do() {
p.cmd.Press()
}
//客户端
func main() {
var tv TV
openCommand := OpenCommand{tv}
invoker := Invoker{openCommand}
invoker.Do()
invoker.SetCommand(CloseCommand{tv})
invoker.Do()
}
命令模式实现起来也很简单,它降低了系统的耦合度,并且还可以任意扩展使用不需要修改代码,开闭原则体现的淋漓尽致。
接下来介绍复合命令,也叫宏命令,复合命令其实说白了就是将多个命令保存起来,通过遍历这个集合来分别调用各个命令。
package main
import "fmt"
//电视类
type TV struct {
}
func (p TV) Open() {
fmt.Println("Play...")
}
func (p TV) Close() {
fmt.Println("Stop...")
}
//遥控器上的按键
type Command interface {
Press()
}
type OpenCommand struct {
tv TV
}
func (p OpenCommand) Press() {
p.tv.Open()
}
type CloseCommand struct {
tv TV
}
func (p CloseCommand) Press() {
p.tv.Close()
}
//调用者(遥控器)
type Invoker struct {
cmd Command
}
func (p *Invoker) SetCommand(cmd Command) {
p.cmd = cmd
}
func (p *Invoker) Do() {
p.cmd.Press()
}
func NewOpenCloseCommand() *OpenCloseCommand {
var openClose *OpenCloseCommand = &OpenCloseCommand{}
openClose.cmds = make([]Command, 2)
return openClose
}
type OpenCloseCommand struct {
index int
cmds []Command
}
func (p *OpenCloseCommand) AddCommand(cmd Command) {
p.cmds[p.index] = cmd
p.index++
}
func (p OpenCloseCommand) Press() {
for _, item := range p.cmds {
item.Press()
}
}
func main() {
var tv TV
var openClose *OpenCloseCommand = NewOpenCloseCommand()
openClose.AddCommand(OpenCommand{tv})
openClose.AddCommand(CloseCommand{tv})
invoker := Invoker{openClose}
invoker.SetCommand(openClose)
invoker.Do()
}