golang接口的封裝


 

一、聲明接口

1 type Result interface { 2  LastInsertId() (int64, error) 3  RowsAffected() (int64, error) 4 }

 

二、實現接口,這里卻將接口作為成員變量,進而將接口的實現轉換為接口的調用,僅僅是封裝了接口,實際上並沒有真的實現,而是坐等別人去實現

 1 // 一把鎖  2 // 一個結果集的假接口實現,表示需要的功能,讓他人來具體實現。假裝實現了某個接口,其實是調用了內部接口的對應方法
 3 type driverResult struct {  4  sync.Locker  5  resi driver.Result  6 }  7 // Result 是對已執行 SQL 命令的總結,。  8 // LastInsertId() 會返回一個由數據庫生成的整數, 這個整數是對命令的響應。 在插入一個新的數據行時, 這個整數通常來源於數據表中的自增數據列。  9 // 並不是所有數據庫都支持這個特性, 並且各個數據庫在實現這個特性時使用的語句也會有所不同。 10 // RowsAffected() 返回受到更新、插入或者刪除操作影響的行數量, 並不是所有數據庫或者所有數據庫驅動都支持這個特性。
11 type Result interface { 12  LastInsertId() (int64, error) 13  RowsAffected() (int64, error) 14 } 15 
16 func (dr driverResult) LastInsertId() (int64, error) { 17  dr.Lock() 18  defer dr.Unlock() 19     return dr.resi.LastInsertId() 20 } 21 
22 func (dr driverResult) RowsAffected() (int64, error) { 23  dr.Lock() 24  defer dr.Unlock() 25     return dr.resi.RowsAffected() 26 }

 

Go 中的 interface 是一種類型,更准確的說是一種抽象類型 abstract type,一個 interface 就是包含了一系列行為的 method 集合,interface 的定義很簡單:

 

1 package io
2 
3 type Writer interface {
4     Write(p []byte) (n int, err error)
5 }

 

 

如果一個 concrete type 實現了某個 interface,我們說這個 concrete type 實現了 interface 包含的所有 method,必須是所有的 method。Go 中的 interface 不同於其它語言,它是隱式的 implicitly,這意味着對於一個已有類型,你可以不用更改任何代碼就可以讓其滿足某個 interface。

在 Go 的標准庫 fmt 中有一系列的方法可以很好的詮釋 interface 是如何應用到實踐當中的。

 

 1 package fmt
 2 
 3 func Fprintf(w io.Writer, format string, args ...interface{}) (int, error)
 4 
 5 func Printf(format string, args ...interface{}) (int, error) {
 6     return Fprintf(os.Stdout, format, args...)
 7 }
 8 
 9 func Sprintf(format string, args ...interface{}) string {
10     var buf bytes.Buffer
11     Fprintf(&buf, format, args...)
12     return buf.String()
13 }

 

 

 

在 Printf 函數中,調用 Fprintf 時指定的輸出是標准輸出,這正是 Printf 的功能:Printf formats according to a format specifier and writes to standard output,根據指定的格式化要求輸出到標准輸出,os.Stdout 的類型是 *os.File 。Fprintf 中的前綴 F 表示 File,意思是格式化的輸出被輸出到函數指定的第一個 File 類型的參數中。

同樣在 Sprintf 函數中,調用 Fprintf 時指定的輸出是一個指向某個 memory buffer 的指針,其類似一個 *os.File

雖然 bytes.Buffer 和 os.Stdout 是不同的,但是它們都可以被用於調用同一個函數 Fprintf,就是因為 Fprintf 的第一個參數是接口類型 io.Writer ,而 bytes.Buffer 和 os.Stdout 都實現了這個 interface,即它們都實現了 Write 這個 method,這個 interface 並不是一個 File 卻完成了類似 File的功能。

Fprintf 其實並不關心它的第一個參數是一個 file 還是一段 memory,它只是調用了 Write method。這正是 interface 所關注的,只在乎行為,不在乎其值,這種能力讓我們可以非常自由的向 Fprintf 傳遞任何滿足 io.Writer 的 concrete type,這是 Go interface 帶來的 substitutability 可替代性,object-oriented programming 的一種重要特性。

看個例子:

 

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 type ByteCounter int
 8 
 9 
10 func (c *ByteCounter) Write(p []byte) (int, error) {
11     *c += ByteCounter(len(p)) // convert int to ByteCounter
12     return len(p), nil
13 }
14 
15 func main() {
16 
17     var c ByteCounter
18     c.Write([]byte("hello"))
19     fmt.Println(c) // 5  #1
20     fmt.Fprintf(&c, "hello") #2 
21     fmt.Println(c) // 10  #3
22 }

 


這就是 Go 中的 interface 所具有的最基本的功能:作為一種 abstract type,實現各種 concrete type 的行為統一。
ByteCounter
 實現了 Write method,它滿足 io.Writer interface,Write method 計算傳給它的 byte slice 的長度並且賦值給自身,所以 #1 輸出到標准輸出的是它的值 5,正如前文所言,調用 fmt.Fprintf 時再次調用了 c 的 Write method,所以 #3 輸出是 10。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM