在 go
开发中,首先遇到的一个问题,应该怎么设计开发架构。一个好的架构能够在后续的我的项目开发中可能更好的应用我的项目的推动,同时可能让团队的配合更加的顺利。
一个简洁的架构应该具备如下几个特点:
- 不依赖框架:好的架构该当是独立的,不依赖框架可扩大的
- 不依赖 UI:UI 应该很容易批改,而不须要改业务局部代码
- 独立于数据库:不绑定数据库,能够在不改变业务代码的状况下,更换其余数据库
- 可测试的:可能比拟不便测试用例的编写
上面目录构造引自 《go 整洁模板》
├─cmd 利用入口
│ └─app
├─config
├─docs // 寄存文档
├─internal
│ ├─app
│ ├─controller // 控制器
│ │ ├─amqp_rpc
│ │ └─http
│ │ └─v1
│ ├─entity // 实体层
│ ├─middleware // 中间件
│ └─usecase
│ ├─repo // 数据库操作
│ └─webapi // RESTful API
├─migrations
├─pkg // 以被内部程序平安导入的包
│ ├─crypto
│ ├─httpresponse
│ ├─httpserver
│ ├─logger
│ ├─mysql
│ ├─postgres
│ ├─rabbitmq
│ └─redis
分层介绍
层级调用是通过外层 -> 内层,内层是不晓得外层的存在的。在内层代码中,不应该援用外层申明的:变量、类、办法,构造体。
这样做能够保障内层的独立,如果外层扭转,不会对内层造成影响。
这里层级有四层别离为:实体(Entities)、用例(Use Cases)、接口适配器(Interface Adapters)、框架和驱动因素(Frameworks and Drivers)。
构造的层级并不是固定的,能够依据本身需要在此基础上进行增减。
实体(Entities)internal/entity
实体相似于 MVC 中的 M 层,定义了应用程序的业务对象,实体除了定义构造体外,还能够有相干办法(参数校验)。
用例(usecase) internal/usecase
业务逻辑.
- 办法按应用领域分组(在独特的根底上)
- 每个组都有本人的构造
- 一个文件对应一个构造 Repositories、webapi、rpc 等业务逻辑构造被注入到业务逻辑构造中
接口适配器(Interface Adapters)internal/controller
该层级次要用于数据传递,以 API 调用为例,将用户传递的参数进行整顿成用例 (usecase) 所需的数据格式,接管用例(usecase) 解决后返回的数据转换成响应的数据。
框架和驱动因素(Frameworks and Drivers)
最外层通常由框架和工具组成,如数据库、Redis、Web 框架等。一般来说,除了与向内的下一个环通信的粘合代码外,这一层不会波及到代码的编写。
调用逻辑
层级调用应该是从外层 -> 内层,以一个 HTTP 申请为例:
HTTP > usecase
usecase > repo
usecase < repo
HTTP < usecase
这里须要留神 usercase 不能间接调用 Postgres,这样违反了依赖准则,使内层(usecase)晓得了外层 (Postgres) 的存在。
应该在 usercase 中定义接口(interface),在外层应用 Postgres 实现该接口。通过依赖注入的模式,将实现的接口注入到 usecase 中,而后 usecase 通过接口进行操作 Postgres。
如上图所示,usercase/Article 依赖 usecase/ArticleOpt 接口查问 Postgres。外层的 repo/Article 对 usecase/ArticleOpt 接口的实现。在初始化 usercase/Article 时,将 repo/Article 注入 usercase/Article,usercase/Article 就能够通过注入的具体实现 (repo/Article) 实现 Postgres 查问。
总结
此架构模式通过依赖注入的形式来保障各个层级间的独立,不会因为某个层级的改变而影响其余层。
对于程序的扩大也是非常不便,因为层级的之间并不相互依赖而是依赖对应的接口,这样如果须要更换某个组件只须要实现对应接口的实现就能够实现组件的替换,无需批改业务代码和其余层级中的代码改变。
参考链接
- go-clean-template
- The Clean Architecture article