2015-09-09 32 views
1

圍繞何時使用方法和功能的最佳做法是什麼?去最佳實踐:函數與模糊接收器的方法?

具體來說,我有2個結構:probeManagerprobeWorker,我正在寫一個函數run需要訪問兩個結構的成員。這可以解釋爲,告訴經理運行輔助,或呼籲工人奔跑和傳球經理進行訪問,或者我可以創建一個運行功能,這既需要作爲參數:

func (m *ProbeManager) run(w *ProbeWorker) { ... } 
func (w *ProbeWorker) run(m *ProbeManager) { ... } 
func run(m *ProbeManager, w *ProbeWorker) { ... } 

由於所有3種方法在語義上是有效的,一種方法比另一種方法有什麼優點,或者這是否符合個人偏好?

+0

您可以粘貼一個比特的遊碼? 「可行的方式」是儘可能使用小型接口,但如果這是一種替代方案,給定的信息是不可能的。 –

+0

@PabloFernandez [這裏](https://gist.github.com/timstclair/a4582cd48bc567c8576a)是完整的方法。請注意,這是更大的未完成更改的一部分,我不確定它是否編譯。同樣的問題也適用於doProbe,爲了清楚起見,它們分開。 –

回答

0

它們都是實際上等價的。接收器像其他參數一樣傳入方法。既然你需要兩種類型(不管是什麼(調用方法)),它的定義並不重要。就我個人而言,我會用你最後的三個選項。這對我來說更有意義,因爲在其他情況下,當將方法與這兩種類型中的一種關聯時,實際上它們都需要這兩種類型。這只是你想如何組織代碼的問題。對於性能或應用程序行爲,其他人不會從中受益,它們都是一樣的。

編輯:最後一點。這些都不會被導出,因此它是一個'私人'或者更確切地說是一個用作包裝內部幫手的方法。更多理由不具備接收類型。

1

使用方法允許您定義接口。假設你有:

func (m *ProbeManager) Run(w *ProbeWorker) {} 

您可以創建一個接口:

type Manager interface { 
    Run(w *ProbeWorker) 
} 

現在任何接過*ProbeManager可以採取Manager代替。這從它的實現細節中分解了Run。有很多原因,這是有益的:

  • 這使得代碼更易於推理,更易於安全地改變,因爲它隱藏了不必要的細節(information hiding
  • 這使得代碼更易於測試,你可以模擬出接口和隔離測試代碼的一小部分:

    type mockManager struct { 
        run func(w *ProbeWorker) 
    } 
    
    func (m mockManager) Run(w *ProbeWorker) { 
        m.run(w) 
    } 
    
    func Test(t *testing.T) { 
        wasCalled := false 
        m := mockManager{ 
         run: func(w *ProbeWorker) { 
          wasCalled = true 
         }, 
        } 
        // pass m to something that takes a Manager 
    } 
    
  • 接口也給你實現dependency injection的能力。有許多方法,但一個很簡單的一個是提供一個Default實現:

    var DefaultManager Manager = &ProbeManager{} 
    

    或基於字符串的註冊表:

    var managerLookup = map[string]Manager{} 
    
    func RegisterManager(nm string, m Manager) { 
        managerLookup[nm] = m 
    } 
    
    func GetManager(nm string) Manager { 
        return managerLookup[nm] 
    } 
    

    這是非常強大的,因爲它可以讓你修改的行爲現有的軟件包無需更改其代碼。 (例如,假設您有一個文件下載器,並且您實施了http支持。其他人可以提供ftp支持,並且解析URL所需的代碼不需要使用此註冊表方法進行更改)

  • 接口允許您實現類似的方法來解決其他編程語言中會遇到的問題。它們爲您提供了一種通用多態(參見sort包),您可以通過實現調用相同接口的接口來實現面向方面編程或猴子補丁(考慮調用基礎Filegzip.Reader。任何需要io.Reader的東西也可以採取gzip.Reader,讓您替代行爲,而無需更改代碼的其餘部分)

我可以繼續下去...

+0

好點我沒有想到,但他的方法沒有出口,所以我不認爲他們可以實現一個接口?這不是我確定的主題,但是如果在不需要接口的範圍之外暴露的方法實現接口就沒有任何意義。 – evanmcdonnal

+0

最後一段中描述的編碼風格也經常被稱爲* decorator *模式。 AO和猴子補丁通常意味着,此外,還有一些聰明的內部foo,也許是在字節碼級別。 Go中並不是這種情況,這是一種簡單直接的免費模式,所以* decorator *這個詞更合適。 –