什么是Golang的正交組合-水平組合思維:Tony Bai的博客 - Coding in GO way - Orthogonal Composition
這篇文章研究其中提到的 interface wrapper function。
//show/show.go
package show
type Shower interface {
Show()
}
這是一個最簡單的,定義了一個Shower的接口并聲明了Show方法,滿足這個接口的類型Type.Show()
將在屏幕顯示用戶定義的一段文字。
隨后我們需要為這個Shower接口添加一個實例。例如我們添加一個數據類型使他能夠顯示Demo:
user-string
:
//demo/demo.go
package demo
type Show struct {
s string
}
func (this *Show) Show(){
fmt.Println("Demo:",this.s)
}
這段代碼是否應該屬于package show
?不是,因為實現Show()方法不止這一種。例如我們還可以:
//demo2/demo.go
package demo2
type Show struct {
s string
}
func (this *Show) Show(){
fmt.Println("This is another Demo: ",this.s)
}
接下來我們可以在main.go中使用這個接口和對應的方法:
//main.go
package main
import(
"show"
"demo"
"demo2"
)
func main(){
var ds show.Shower = &demo.Show{"string from main"}
var d2s show.Shower = &demo2.Show{"string from main"}
ds.Show()
}
我們一般用一個函數來包裝參數,使之直接返回一個接口類型。這是interface warp function的其中一種用法:
//demo/demo.go
func NewShow(s string) show.Shower {return &Show{s}}
//demo.Show不是Shower接口的實現類型,*demo.Show才是
在main.go中使用這個方法來創建接口:
//main.go
ds := demo.NewShow("string from main")
ds.Show()
注意在寫interface warp的時候返回類型必須是接口類型,即func NewShow(s string) Show {return &Show{s}}
或func NewShow(s string) *Show {return &Show{s}}
都是錯誤的。雖說他們或許可以成功執行ds.Show()
操作,但他們都只是一個結構體,也就是執行ds.(show.Shower)
類型斷言時編譯器會拋出錯誤。
以上都是很基礎的部分。接下來我們考慮一個需求,即我們需要用一個方法(接口)來實現將字符串連續打印多遍的功能。例如在stl中LimitedReader
的實現方法。為此,我們創建一個結構體ShowMultiTimes并繼承Shower:
//which package does it belong??
type ShowMutliTimes_s struct {
n int //n times
}
func (this *ShowMultiTimes_s) Show(){
for i:=0;i<this.n;i++{
//??
}
}
可以發現,這個方法應該同時對所有Shower的實現類型生效。同時他打印的內容也與Shower的實現類型(如Demo,Demo2)有關,因此他應該是一個屬于package show的方法:
package show
import "fmt"
type ShowMultiTimes struct {
S Shower
n int
}
func (this *ShowMultiTimes) Show(){
for i:=0;i<this.n;i++{
fmt.Print("Time",i,": ")
this.S.Show()
}
}
我們說interface wrapper function的第二種用法,即接受interface類型參數,并返回與其參數類型相同的返回值。
func ShowNTimes(s Shower, n int) Shower {return &ShowMultiTimes{s,n}}
ShowNTimes是一個wrapper function,它在s的外面再包裹上ShowMultiTimes。通過wrapper function將NewShow和ShowMultiTimes 的兩者巧妙的組合在了一起。這樣當我們采用包裝后的Shower去Read時,輸出的是經過處理后的字符串了。
//main.go
package main
import(
"show"
"demo"
"demo2"
)
func main(){
st:=show.ShowNTimes(test.NewShowI("String from main"),3)
st.Show()
}
可以看到,interface warp function可以組合成一個chain,因為其wrapper function返回值類型與parameter類型相同。