什麼是 Command Pattern?
將建立指令與實際執行分離
問題情境
PS5 有特定操作 CPU 指令的實作.ACommand()
、.BCommand()
,如果現在又多了新的特定操作,必須修改PS5{}
,這不符合開閉原則,我們需要有方法滿足開閉原則。
package main
import "fmt"
type CPU struct{}
func (CPU) ADoSomething() {
fmt.Println("a do something")
}
func (CPU) BDoSomething() {
fmt.Println("b do something")
}
func (CPU) CDoSomething() {
fmt.Println("c do something")
}
type PS5 struct {
cpu CPU
}
func (p PS5) ACommand() {
p.cpu.ADoSomething()
p.cpu.CDoSomething()
}
func (p PS5) BCommand() {
p.cpu.ADoSomething()
p.cpu.BDoSomething()
}
func main() {
cpu := CPU{}
ps5 := PS5{cpu}
ps5.ACommand()
ps5.BCommand()
}
解決方式
新增Command
interface,裡頭有Execute()
這個 function,並實作ACommand{}
、BCommand{}
,讓指令的建立從PS5{}
中分離出來,即滿足開閉原則。
最後透過PS5{}.SetCommand()
來將符合Command
interface 的指令設定給 PS5,再透過PS5{}.DoCommand()
選擇要執行的指令。
package main
import "fmt"
type CPU struct{}
func (CPU) ADoSomething() {
fmt.Println("a do something")
}
func (CPU) BDoSomething() {
fmt.Println("b do something")
}
func (CPU) CDoSomething() {
fmt.Println("c do something")
}
type Command interface {
Execute()
}
type ACommand struct {
cpu CPU
}
func (a ACommand) Execute() {
a.cpu.ADoSomething()
a.cpu.CDoSomething()
}
type BCommand struct {
cpu CPU
}
func (b BCommand) Execute() {
b.cpu.ADoSomething()
b.cpu.BDoSomething()
}
type PS5 struct {
commands map[string]Command
}
func (p *PS5) SetCommand(name string, command Command) {
p.commands[name] = command
}
func (p *PS5) DoCommand(name string) {
p.commands[name].Execute()
}
func main() {
cpu := CPU{}
aCommand := ACommand{cpu}
bCommand := BCommand{cpu}
ps5 := PS5{make(map[string]Command)}
ps5.SetCommand("a", aCommand)
ps5.SetCommand("b", bCommand)
ps5.DoCommand("a")
ps5.DoCommand("b")
}