go项目分层与工厂模式 | 青训营笔记

51 阅读2分钟

分模块/分层

现代软件往往是复杂而多变的,对于一个大型系统,一个最为显而易见且直接的办法是对这个大型系统进行拆分,一种最常见的拆分方式是:

  1. 由高到低按照逻辑层次进行拆分
  2. 同一个逻辑层次按照功能模块进行模块拆分 这种拆分会极大的降低系统的复杂度,也利于这个系统开发工作的分工。

分层有很多好处,以 TCP/IP 为例:

  1. 分层有利标准化工作,TCP/IP 就是关于他们各个层次如何工作的标准
  2. 层次依赖降低,某层的实现可以替换而不影响其他层的工作
  3. 降低整体的复杂度,TCP/IP 各个层次对行为、标准变得简单

Go 项目的分层

分层的方式多种多样,《企业应用架构模式》中主要采用这样的分层结构:

  • 表现层:提供服务,处理、验证 Http 请求等
  • 领域层:逻辑核心
  • 数据源层:与数据库、消息队列以及其他软件通信
  • 类似但是稍有不同的还有 其他划分办法 (Marinescu/Brown 等5层结构,Nilson 7层结构等),但是如同 tcp/ip 的7层/5层划分,尽管多层次让系统变得更为清晰,但是同时也带来了更多复杂度。

依赖注入与工厂模式

依赖对象新建一般来说常见有几种方法

  1. 直接新建:A 依赖 B,直接 new B
  2. 工厂:通过 B 工厂或者一个 通用工厂生产 B
  3. 依赖注入:自动新建注入 A 依赖的 B

依赖注入的研发模式在 JAVA 工程中应用非常广泛,而在 Go 项目中尚未普及,比如facebook inject、uber dig、google wire,这些框架使用起来并没有特别方便,这是和 golang 的动态 能力不够有关系。大部分的依赖注入框架使用 tag 标记或者代码生成的方式进行处理,往往并不像 JAVA 中那么 自动化。 参考依赖注入的实现方式,在 Golang 中实现一套手动注入的抽象工厂,把依赖对象的创建逻辑集中到一处,比如下面的这个例子,本质也是一套抽象工厂:

var st store.Interface
var storeOnce sync.Once

func ProvideStore() storeInterface {
	storeOnce.Do(func() {
			st = NewStore(config.DbUri)
	})
	return st
}

func ProvideRemoteAClient() remoteAInterface {
	return NewRemoteAClient(config.remoteAUri)
}

func ProvideServiceA() serviceAInterface {
	return NewServiceA(ProvideStore())
}

func ProvideServiceB() serviceBInterface {
	return NewServiceB(ProvideStore(), ProvideRemoteAClient())
}