1
0
mirror of https://github.com/chai2010/advanced-go-programming-book.git synced 2025-05-24 04:22:22 +00:00

update interface section

This commit is contained in:
Xargin 2018-03-26 17:13:46 +08:00
parent cc73ebb925
commit 467d44a01c

View File

@ -16,11 +16,11 @@ TODOTODO 这里有图,标明控制流的方向
从架构的角度讲,这个控制流会给我们带来很多问题:
```
1. dao 的变动必然会引起 logic 的变动
2. 核心的业务逻辑 logic 代码变动会给我们带来较大的风险
3.
```
3. 项目的依赖于大量的外部服务、组件,难以测试
本节主要解决 1 和 2 两个问题。
interface 这时候就成为了我们的救星,如果我们在 a->b 这个控制方向上不满意,不想让 b 的变化引起 a 的不适,那么我们就在 a 与 b 之间插入一层 interface。
@ -36,14 +36,77 @@ TODOTODO这里是控制流和依赖流的示意图。
![插件化架构](../images/ch6-08-plugin-arch.jpg)
dao 成为了 logic 的 plugin(插件)。如果我们要把 dao 里的 kv 数据库从 rocksdb(假如) 替换为自研的 thrift 协议 kv 存储,那么新的 dao 实现也只要遵从之前定义好的 interface 就可以logic 不需要任何变化。这就是所谓的插件化架构。
dao(DB) 成为了 logic(business rules) 的 plugin(插件)。如果我们要把 dao 里的 kv 数据库从 rocksdb(假如) 替换为自研的 thrift 协议 kv 存储,那么新的 dao 实现也只要遵从之前定义好的 interface 就可以logic 不需要任何变化。这就是所谓的插件化架构。
## 实例
稍微具体一点:
```go
type RecordSaver interface {
func Save(r MyRecord) error
// src/dto
type Order struct {
OrderID int64
UserID int64
ProductID int64
CreateTime time.Time
}
// src/logic
type OrderRep interface {
func Save(r dto.Order) error
func Get(orderID int64) (dto.Order, error)
}
// one of many dependencies
var orderService OrderRep
// init order dependency
func InitOrderService(os OrderRep) error {
orderService = os
}
// api provided by logic
func CreateOrder(orderID int64, userID int64, productID int64, createTime time.Time) error {
o := Order{
OrderID : orderID,
UserID : userID,
ProductID : productID,
CreateTime : createTime,
}
err := orderService.Save(o)
if err != nil {
// do someth
return err
}
return nil
}
// src/dao/order
type OrderService struct {}
func (od *OrderService) Save(r dto.Order) error {
// save this order
return nil
}
func (od *OrderService) Get(orderID int64) (dto.Order, error) {
// save this order
return nil
}
// src/main
func initAllDependencies() {
// order service init
orderService := orderdao.OrderService{}
orderlogic.InitOrderService(orderService)
}
```
##
上面是一个简单将 order 的 dao 层和 logic 进行控制反转的例子。有了这种手段我们可以将控制流中logic 所有下层逻辑全部变成 logic 的插件。
用这种控制反转手段把我们的核心业务逻辑隔离出来的手段实际上也存在着一些争议Uncle Bob 认为这是最佳实践,哪怕我们的项目模块没有那么复杂,也应该允许把这些内部的 interface 先设计好,并保留在项目中,以方便日后的扩展。但 interface 的引入多多少少会给项目带来一定程度的复杂性,而且有一部分 IDE 对 interface 的支持并不是非常好(比如非常流行的 vscode在查找 interface 的 implementation 时就极其缓慢)。
总的来说interface 依然是一种非常理想的手段,就算短时间内用不上。在未来某一天你被反复变动的下游逻辑恶心到的时候,就会对这种控制反转手段理解更为深刻了吧。