Go語言使用事件系統實現事件的晌應和處理

2020-07-16 10:05:01
Go語言可以將型別的方法與普通函數視為一個概念,從而簡化方法和函數混合作為回撥型別時的複雜性。這個特性和 C# 中的代理(delegate)類似,呼叫者無須關心誰來支援呼叫,系統會自動處理是否呼叫普通函數或型別的方法。

本節中,首先將用簡單的例子了解 Go語言是如何將方法與函數視為一個概念,接著會實現一個事件系統,事件系統能有效地將事件觸發與響應兩端程式碼解耦。

方法和函數的統一呼叫

本節的例子將讓一個結構體的方法(class.Do)的引數和一個普通函數(funcDo)的引數完全一致,也就是方法與函數的簽名一致。然後使用與它們簽名一致的函數變數(delegate)分別賦值方法與函數,接著呼叫它們,觀察實際效果。詳細實現請參考如下程式碼。
package main

import "fmt"

// 宣告一個結構體
type class struct {
}

// 給結構體新增Do方法
func (c *class) Do(v int) {

    fmt.Println("call method do:", v)
}

// 普通函數的Do
func funcDo(v int) {

    fmt.Println("call function do:", v)
}

func main() {

    // 宣告一個函數回撥
    var delegate func(int)

    // 建立結構體範例
    c := new(class)

    // 將回撥設為c的Do方法
    delegate = c.Do

    // 呼叫
    delegate(100)

    // 將回撥設為普通函數
    delegate = funcDo

    // 呼叫
    delegate(100)
}
程式碼說明如下:
  • 第 10 行,為結構體新增一個 Do() 方法,引數為整型。這個方法的功能是列印提示和輸入的引數值。
  • 第 16 行,宣告一個普通函數,引數也是整型,功能是列印提示和輸入的引數值。
  • 第 24 行,宣告一個 delegate 的變數,型別為 func(int),與 funcDo 和 class 的 Do() 方法的引數一致。
  • 第 30 行,將 c.Do 作為值賦給 delegate 變數。
  • 第 33 行,呼叫 delegate() 函數,傳入 100 的引數。此時會呼叫 c 範例的 Do() 方法。
  • 第 36 行,將 funcDo 賦值給 delegate。
  • 第 39 行,呼叫 delegate(),傳入 100 的引數。此時會呼叫 funcDo() 方法。

執行程式碼,輸出如下:

call method do: 100
call function do: 100

這段程式碼能執行的基礎在於:無論是普通函數還是結構體的方法,只要它們的簽名一致,與它們簽名一致的函數變數就可以儲存普通函數或是結構體方法。了解了 Go語言的這一特性後,我們就可以將這個特性用在事件中。

事件系統基本原理

事件系統可以將事件派發者與事件處理者解禍。例如,網路底層可以生成各種事件,在網路連線上後,網路底層只需將事件派發出去,而不需要關心到底哪些程式碼來響應連線上的邏輯。或者再比如,你註冊、關注或者訂閱某“大V”的社交訊息後,“大V”發生的任何事件都會通知你,但他並不用了解粉絲們是如何為她喝彩或者瘋狂的。如下圖所示為事件系統基本原理圖。

事件系統基本原理
圖:事件系統基本原理