Golang核心编程(6)-面向对象之接口

版权声明: https://blog.csdn.net/pbrlovejava/article/details/83962440


更多关于Golang核心编程知识的文章请看:Golang核心编程(0)-目录页


一、其他语言的侵入式接口

Go语言的接口并不是其他语言(C++、Java、C#等)中所提供的接口概念。
在Go语言出现之前,接口主要作为不同组件之间的契约存在。对契约的实现是强制的,你必须声明你的确实现了该接口。为了实现一个接口,你需要从该接口继承:

interface IFoo {
void Bar();
}
class Foo implements IFoo { // Java文法
// ...
}
class Foo : public IFoo { // C++文法
// ...
}
IFoo* foo = new Foo;

即使另外有一个接口 IFoo2 实现了与 IFoo 完全一样的接口方法甚至名字也叫 IFoo 只不过位于不同的名字空间下,编译器也会认为上面的类 Foo 只实现了 IFoo 而没有实现 IFoo2 接口。

这类接口我们称为侵入式接口。“侵入式”的主要表现在于实现类需要明确声明自己实现了某个接口。这种强制性的接口继承是面向对象编程思想发展过程中一个遭受相当多置疑的特性。

二、 Golang的非侵入式接口

在Go语言中,一个类只需要实现了接口要求的所有函数,我们就说这个类实现了该接口,例如:

type File struct {
// ...
}
func (f *File) Read(buf []byte) (n int, err error)
func (f *File) Write(buf []byte) (n int, err error)
func (f *File) Seek(off int64, whence int) (pos int64, err error)
func (f *File) Close() error

这里我们定义了一个 File 类,并实现有 Read() 、 Write() 、 Seek() 、 Close() 等方法。设想我们有如下接口:

type IFile interface {
Read(buf []byte) (n int, err error)
Write(buf []byte) (n int, err error)
Seek(off int64, whence int) (pos int64, err error)
Close() error
}

type IReader interface {
Read(buf []byte) (n int, err error)
}

type IWriter interface {
Write(buf []byte) (n int, err error)
}

type ICloser interface {
Close() error
}

尽管 File 类并没有从这些接口继承,甚至可以不知道这些接口的存在,但是 File 类实现了
这些接口,可以进行赋值:

var file1 IFile = new(File)
var file2 IReader = new(File)
var file3 IWriter = new(File)
var file4 ICloser = new(File)

Go的非侵入式接口有许多好处:

其一,在Go中,类的继承树并无意义,你只需要知道这个类实现了哪些方法,每个方法是啥含义就足够了。
其二,实现类的时候,只需要关心自己应该提供哪些方法,不用再纠结接口需要拆得多细才
合理。接口由使用方按需定义,而不用事前规划。
其三,不用为了实现一个接口而导入一个包,因为多引用一个外部的包,就意味着更多的耦
合。接口由使用方按自身需求来定义,使用方无需关心是否有其他模块定义过类似的接口。

三、 接口判断

接口查询语法,代码如下:

var file1 Writer = ...
if file5, ok := file1.(two.IStream); ok {
...
}

这个 if 语句检查 file1 接口指向的对象实例是否实现了 two.IStream 接口,如果实现了,则执行特定的代码。

接口查询是否成功,要在运行期才能够确定。它不像接口赋值,编译器只需要通过静态类型检查即可判断赋值是否可行。

四、类型查询

在Go语言中,还可以更加直截了当地询问接口指向的对象实例的类型,例如:

	var v1 interface{} = ...
	switch v := v1.(type) {
	case int: // 现在v的类型是int
	case string: // 现在v的类型是string
	...
}

五、接口组合

Go语言同样支持接口组合。我们已经介绍过Go语言包中 io.Reader接口和 io.Writer 接口,接下来我们再介绍同样来自于 io 包的另一个接口 io.ReadWriter :

	// ReadWriter接口将基本的Read和Write方法组合起来
	type ReadWriter interface {
	Reader
	Writer
	}

这个接口组合了 Reader 和 Writer 两个接口,它完全等同于如下写法:

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

因为这两种写法的表意完全相同: ReadWriter 接口既能做 Reader 接口的所有事情,又能做
Writer 接口的所有事情。在Go语言包中,还有众多类似的组合接口,比如 ReadWriteCloser 、ReadWriteSeeker 、 ReadSeeker 和 WriteCloser 等。
可以认为接口组合是类型匿名组合的一个特定场景,只不过接口只包含方法,而不包含任何成员变量。

六、Any 类型

由于Go语言中任何对象实例都满足空接口 interface{} ,所以 interface{} 看起来像是可
以指向任何对象的 Any 类型,如下:

var v1 interface{} = 1 // 将int类型赋值给interface{}
var v2 interface{} = "abc" // 将string类型赋值给interface{}
var v3 interface{} = &v2 // 将*interface{}类型赋值给interface{}
var v4 interface{} = struct{ X int }{1}
var v5 interface{} = &struct{ X int }{1}

猜你喜欢

转载自blog.csdn.net/pbrlovejava/article/details/83962440