0
点赞
收藏
分享

微信扫一扫

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。



举报

相关推荐

0 条评论