Skip to content

Commit

Permalink
Merge pull request #151 from syjs10/master
Browse files Browse the repository at this point in the history
Tip #18: Define interfaces in the consumer package, not the producer
  • Loading branch information
smallnest authored Apr 24, 2024
2 parents 4e44c49 + 5344f10 commit c32a88a
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 1 deletion.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
62 changes: 62 additions & 0 deletions src/018.md
Original file line number Diff line number Diff line change
@@ -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测试和设计思维。
1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Binary file added src/images/018/tips018-img1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/images/018/tips018-img2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/images/018/tips018-img3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/images/018/tips018-img4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit c32a88a

Please sign in to comment.