接口|青训营

56 阅读2分钟

接口代表一种调用契约,是多个方法声明的集合。

接口解除了类型依赖,有助于减少用户可视方法,屏蔽内部结构和实现细节。似乎好处很多,但这并不意味着可以滥用接口,毕竟接口实现机制会有运行期开销。对于相同包,或者不会频繁变化的内部模块之间,并不需要抽象出接口来强行分离。接口最常见的使用场景,是对包外提供访问,或预留扩展空间。

在某些动态语言里,接口(interface)也被称作协议(protocol)。准备交互的双方,共同遵守事先约定的规则,使得在无须知道对方身份的情况下进行协作。接口要实现的是做什么,而不关心怎么做,谁来做。

接口解除了类型依赖,有助于减少用户可视方法,屏蔽内部结构和实现细节。似乎好处很多,但这并不意味着可以滥用接口,毕竟接口实现机制会有运行期开销。对于相同包,或者不会频繁变化的内部模块之间,并不需要抽象出接口来强行分离。接口最常见的使用场景,是对包外提供访问,或预留扩展空间。

Go接口实现机制很简洁,只要目标类型方法集内包含接口声明的全部方法,就被视为实现了该接口,无须做显示声明。当然,目标类型可实现多个接口。

换句话说,我们可以先实现类型,而后再抽象出所需接口。这种非侵入式设计有很多好处。举例来说:在项目前期就设计出最合理接口并不容易,而在代码重构,模块分拆时再分离出接口,用以解耦就很常见。另外,在使用第三方库时,抽象出所需接口,即可屏蔽太多不需要关注的内容,也便于日后替换。

从内部实现来看,接口自身也是一种结构类型,只是编译器会对其做出很多限制。

  • 不能有字段。
  • 不能定义自己的方法。
  • 只能声明方法,不能实现。
  • 可嵌入其他接口类型。

接口通常以er作为名称后缀,方法名是声明组成部分,但参数名可不同或省略。 可以像匿名字段那样,嵌入其他接口。目标类型方法集中必须拥有包含嵌入接口方法在内的全部方法才算实现了该接口。

嵌入其他接口类型,相当于将其声明的方法集导入。这就要求不能有同名方法,因为不支持重载。还有,不能嵌入自身或循环嵌入,那会导致递归错误。