1. 程式人生 > 其它 >Go從入門到精通——介面(interface)——理解型別與介面的關係

Go從入門到精通——介面(interface)——理解型別與介面的關係

理解型別與介面的關係

  型別和介面之間有一對多和多對一的關係,下面將列舉出這些常見的概念,以方便理解介面與型別在複雜環境下的實現關係。

一、一個型別可以實現多個介面

  一個型別可以同時實現多個介面,而介面間彼此獨立,不知道對方的實現。

  網路上的兩個程式通過一個雙向的通訊連線實現資料的交換,連線的一端稱為一個 Socket。Socket 能夠同時讀取和寫入資料,這個特性與檔案類似。因此,開發中把檔案和 Socket 都具備的讀寫特性抽象為獨立的讀寫器概念。

  把 Socket 能夠寫入資料和需要關閉的特性使用介面來描述,程式碼如下:

type Socket struct{
}

func (s *Scoket) Write(p []byte)(n int, err error){
    return 0,nil
}

func (s *Socket) Close() error{
    return nil
}

  Socket 結構的 Write() 方法實現了 io.Writer 介面:

type Writer interface{
    Write(p []byte)(n int, err error)
}

  同時,Socket 結構也實現了 io.Close 介面:

type Closer interface{
    Close() error
}

  使用 Socket 實現的 Writer 介面的程式碼,無須瞭解 Writer 介面的實現者是否具備 Closer 介面的特性。同樣,使用 Close 介面的程式碼也不知道 Socket 已經實現了 Writer 介面。如下圖:

  在程式碼中使用 Socket 結構實現的 Writer 介面和 Closer 介面程式碼如下:

package main

//使用 io.Writer 的程式碼,並不知道 Socket 和 io.Closer 的存在
func usingWriter( writer io.Writer){
    wirter.Write(nil)
}

//使用 io.Close,並不知道 Socket 和 io.Writer 的存在
func usingCloser( closter io.Closer){
    closter.Close()
}

func main(){

    //例項化 Socket
    s := new(Socket)

    usingWriter(s)

    usingCloser(s)

}

  usingWriter() 和 usingCloser() 完全獨立,互相不知道對方的存在,也不知道自己使用的介面是 Scoket 實現的。

二、多個型別可以實現相同的介面

  一個介面的方法,不一定需要一個型別完全實現,介面的方法可以通過在型別中嵌入其他型別或者結構體來實現。也就是說,使用者並不關心某個介面的方法是通過一個型別完全實現的,還是通過多個結構嵌入到一個結構體中拼湊起來共同實現的。

  Service 介面定義了兩個方法:一個是開啟服務的方法(Start()),一個是輸出日誌的方法(Log())。使用 GameService 結構來實現 Service,GameService 自己的結構只能實現 Start() 方法,而 Service 介面中 Log() 方法已經被一個能輸出日誌的日誌器(Logger)實現了,無須再進行 GameService 封裝,或者重新實現一遍。所以,選擇將 Logger 嵌入到 GameService 能最大程度地避免程式碼冗餘,簡化程式碼結構。程式碼實現如下:

package main

type Service interface {
	Start()
	Log(string)
}

//日誌器
type Logger struct {
}

//實現 Service 的 Log() 方法
func (l *Logger) Log(s string) {
}

//遊戲服務
type GameService struct {
	Logger
}

//實現 Service 的 Start() 方法
func (g *GameService) Start() {
}

func main() {
	var s Service = new(GameService)
	s.Start()
	s.Log("hello")
}

  例項化 GameService,並將例項賦給 Service,s 就可以使用 Start()方法和 Log() 方法,其中,Start() 由 GameService 實現,Log() 方法由 Logger 實現。