天天看點

【寒江雪】Go實作指令模式

Command Pattern

  指令模式将指令包裹在對象中,并傳給調用對象。調用對象尋找處理該指令的合适對象,并把該指令傳給合适的對象,該對象執行指令。

例子

  舉一個例子,在go裡邊調用C語言的代碼,來監聽鍵盤的輸入,并調用與輸入綁定的函數。

  定義事件碼和事件結構。

const (
    EVENT_CODE_KEY = iota
)

type EventCode rune
type EventData interface{}
type Event struct{
    Code EventCode
    Data EventData
}
           

  為了簡單,隻寫一個按鍵的事件。

  定義一個抽象的接口。

type Command interface {
    Execute(EventData)
}
           

  這個接口定義了指令的形式。

  我們想讓使用者可以在外部傳入回調函數,那麼就需要定義一個接收事件的回調函數。

type EventFunc func(Event)
           

  有了回調函數形式,我們還需要一個對象,包含這種函數。這種函數不是Command接口對象。但我們可以把它包裝成Command對象,這裡就用到了擴充卡模式。

type EventFunder struct {
    f EventFunc
}

func (this EventFunder) Execute(data Event) {
    this.f(data)
}

func eventFunder(eventFunc EventFunc) EventFunder {
    return EventFunder{eventFunc}
}
           

  eventFunder就是把一個EventFunc類型的對象轉換為EventFunder,EventFunder實作了Command接口,它屬于Command。

  最後是EventSystem的實作。

type Hash map[EventCode]Command

type EventSystem struct {
    hash Hash
}

func (this *EventSystem) Init() *EventSystem {
    this.hash = make(Hash)
    return this
}

func (this *EventSystem) Map(code EventCode, eventFunc EventFunc) {
    this.hash[code] = eventFunder(eventFunc)
}

func (this *EventSystem) InspectKeyboard() {
    go func() {
        C.init_keyboard()
        for {
            if C.kbhit() > {
                ch := EventCode(C.readch())
                // TODO::generate key event
                this.generateEvent(Event{EVENT_CODE_KEY, ch})
            }
        }
    }()
}

func (this *EventSystem) generateEvent(e Event) {
    v, ok := this.hash[e.Code]
    if ok {
        v.Execute(e)
    }
}

func NewEventSystem() *EventSystem {
    return (&EventSystem{}).Init()
}
           

  EventSystem實際上是一個調用者,它隻接收Command對象。是以要把傳入的函數做适配。

優點

  • 降低了系統耦合度。
  • 新的指令可以很容易添加到系統中去。

缺點

  • 使用指令模式可能會導緻某些系統有過多的具體指令類。

注意事項

  系統需要支援指令的撤銷(Undo)操作和恢複(Redo)操作,也可以考慮使用指令模式,見指令模式的擴充。

有錢的捧個錢場,沒錢的捧個人場。

出來混不容易。

【寒江雪】Go實作指令模式

繼續閱讀