diff --git a/README.md b/README.md index b40673f..5589eb0 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ Go tips from [Phuong Le](https://twitter.com/func25). | 15 | 已认领 | | | 16 | Don't Return -1 or nil to Indicate Error. | kagaya85 | | 17 | Understanding "Return fast, return early" to avoid nested code | icyfire | -| 18 | 已认领 | | +| 18 | Define interfaces in the consumer package, not the producer | syjs10 | | 19 | 已认领 | | | 20 | Pass values, not pointers | smallnest | | 21 | Prefer using a pointer receiver when defining methods | QingyaFan | diff --git a/src/018.md b/src/018.md new file mode 100644 index 0000000..3dc2231 --- /dev/null +++ b/src/018.md @@ -0,0 +1,62 @@ +# Tip #18 在使用者的包中定义接口,而不是提供者的包中定义 + +> 原始链接:[Define interfaces in the consumer package, not the producer](https://twitter.com/func25/status/1756629777107292231) +> + +我之前在推特上提到过这个话题(https://twitter.com/func25/status/1738890734349201903),但它的重要性使我把它列入了这个tips的列表里。 + +现在,有3个原则需要记住: + +1. 在使用者的包中定义接口,而不是提供者的包中定义 + + 接口应该由使用者(使用这个接口的代码)而不是提供者(实现这些接口的代码)来定义。 + + 这种方法使得添加一个新的函数实现更容易,不会影响到使用者。 + +2. 在提供者的包中使用具体类型作为返回值 + + 这很简单,因为我们没有再提供者的包里定义这个接口。 + + 它允许我们在这些类型上添加新方法,而不破坏这个API。 + +3. 避免过早定义接口 + + 只在有明确使用场景下定义接口,确保它们是**必要的**且**设计得当的**。 + +好了,说够了理论和假设。 + +你有没有做过类似的事情? + +![tips018-img1](./images/018/tips018-img1.png) + +在consoleLogger同一个的包中定义Logger接口。 + +然后,每当你想使用它时,你在使用者的包中创建接口(?)。 + +![tips018-img2](./images/018/tips018-img2.png) + +我这么做好多年了,不使用Logger,而是使用库的接口。 + +> “这么做不好吗?” + +可能吧 + +但是遵循我们原则考虑一下这个方法,让我们修改一下它。 + +首先,这是我们新的提供者的logger包: + +![tips018-img3](./images/018/tips018-img3.png) + +1. 我们不再在提供者的包中保留Logger这个接口了。 + +2. 在创建一个提供者包中的Logger时,我们返回一个具体类型,对吧? + +3. 我们避免过早的定义接口,不需要猜测使用者需要什么功能。 + +现在让我们看看我们的使用者是如何用它的呢 + +![tips018-img4](./images/018/tips018-img4.png) + +通过在使用接口的地方(在高级模块中)定义接口,可以确保这些模块依赖于抽象接口而不是具体的实现。 + +啊,这也可以增强模块化,mock测试和设计思维。 \ No newline at end of file diff --git a/src/SUMMARY.md b/src/SUMMARY.md index f85d446..6568bc0 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -16,6 +16,7 @@ - [Tip #14 错误信息不要大写或者以标点结尾](./014.md) - [Tip #16 不要通过返回 -1 或者 nil 来表示错误](./016.md) - [Tip #17 理解“尽快返回、尽早返回”,避免代码嵌套](./017.md) +- [Tip #18 在使用者的包中定义接口,而不是提供者的包中定义](./018.md) - [Tip #20 传递值,而不是指针](./020.md) - [Tip #21 定义方法时,优先使用指针作为接收器](./021.md) - [Tip #22 使用结构体或变长参数简化函数签名](./022.md) diff --git a/src/images/018/tips018-img1.png b/src/images/018/tips018-img1.png new file mode 100644 index 0000000..2a90d92 Binary files /dev/null and b/src/images/018/tips018-img1.png differ diff --git a/src/images/018/tips018-img2.png b/src/images/018/tips018-img2.png new file mode 100644 index 0000000..33dd2f5 Binary files /dev/null and b/src/images/018/tips018-img2.png differ diff --git a/src/images/018/tips018-img3.png b/src/images/018/tips018-img3.png new file mode 100644 index 0000000..3207701 Binary files /dev/null and b/src/images/018/tips018-img3.png differ diff --git a/src/images/018/tips018-img4.png b/src/images/018/tips018-img4.png new file mode 100644 index 0000000..e7e0de0 Binary files /dev/null and b/src/images/018/tips018-img4.png differ