一、基本介绍

接口化是更高层次的抽象。框架组件的设计尽可能使用了接口化,而不是尽可能提供具体实现。接口化设计的最大的好处,是允许使用者自定义实现,来替换组件底层的接口层,以实现很强的灵活性和扩展性。

二、组件接口化

GoFrame 框架的核心组件均采用了接口化设计,举个例子,如下图展示了部分组件的接口化实现概览:

接口化与泛型设计 - 图1

大部分的组件,使用了 Adapter 作为自身接口层的名字,通过 SetAdapter 方法来设置当前的接口实现,通过 GetAdapter 方法获取当前组件的接口实现对象。此外,为了提高易用性,组件都会提供一些默认的 Adapter 实现,可供使用者选择。拿 gsession 组件举例:

接口化与泛型设计 - 图2

底层接口采用了 Storage 进行定义,并提供了 File/Memory/Redis/RedisHashTable 四种实现供选择,默认实现为 File

三、接口化与泛型

组件的接口化设计可扩展性是很高的,但是在具体落地的时候需要结合泛型来实现更灵活的使用。同样拿 gsession 组件举例,参数的返回均采用了泛型,在业务使用时根据需要再转换为对应的数据类型。

提高参数灵活性、简化使用复杂度

在不使用泛型的情况下,我们的接口要么提供各种类型的方法、要么使用 interface{} 类型返回,使用的复杂度都比较高。统一通过泛型的数据类型返回,使得参数类型更加灵活,极大地降低了使用复杂度。

接口化与泛型设计 - 图3

泛型支持转换为各种类型:

接口化与泛型设计 - 图4

根据业务场景需要转换为对应的数据类型。类型转换使用了框架统一的类型转换组件,底层会优先使用断言进行类型识别,以保证转换的效率。

接口化与泛型设计 - 图5

统一使用方式、屏蔽底层影响

针对于一些复杂类型的接口化场景,接口的底层实现上可能会存在外部存储的情况、更会产生序列化/反序列化操作,可能会改变/丢失数据类型。使用泛型将能够通过统一的使用方式屏蔽底层实现的影响。例如以下示例,无论底层 Session 实现如何变化,上层使用均通过泛型的 Scan 方法转换为目标对象。

接口化与泛型设计 - 图6

四、注意事项

虽然框架提供了泛型设计,但是并不推荐在业务中广泛使用泛型。业务层的数据结构设计,包括接口和业务模型数据结构,应当是准确的、确定的。