From 221bcf67578219ed2992f94424c0ba5e76f30c71 Mon Sep 17 00:00:00 2001 From: Xargin Date: Mon, 18 Jun 2018 20:48:01 +0800 Subject: [PATCH] update if --- ch5-web/ch5-08-interface-and-web.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/ch5-web/ch5-08-interface-and-web.md b/ch5-web/ch5-08-interface-and-web.md index 8feae2b..250e69f 100644 --- a/ch5-web/ch5-08-interface-and-web.md +++ b/ch5-web/ch5-08-interface-and-web.md @@ -156,7 +156,7 @@ func BusinessProcess(bi BusinessInstance) { 直接面向 interface 编程,而不用关心具体的实现了。如果对应的业务在迭代中发生了修改,所有的逻辑对平台方来说也是完全透明的。 -## interface 是必须的吗? +## interface 的优缺点 Go 被人称道的最多的地方是其 interface 设计的正交性,模块之间不需要知晓相互的存在,A 模块定义 interface,B 模块实现这个 interface 就可以。如果 interface 中没有 A 模块中定义的数据类型,那 B 模块中甚至都不用 import A。比如标准库中的 `io.Writer`: @@ -200,15 +200,20 @@ func init() { 在 MyType 定义的地方,不需要 `import "io"` 就可以直接实现 `io.Writer` interface,我们还可以随意地组合很多函数,以实现各种类型的接口,同时接口实现方和接口定义方都不用建立 import 产生的依赖关系。因此很多人认为 Go 的这种正交是一种很优秀的设计。 -但这种“正交”性也会给我们带来一些麻烦。当我们接手了一个几十万行的系统时,如果看到定义了很多 interface,例如订单流程的 interface,我们希望能直接找到这些 interface 都被哪些对象实现了。但直到现在,这个简单的需求也就只有 goland 实现了,并且体验尚可。Visual Studio Code 则需要对项目进行全局扫描,来看到底有哪些 struct 实现了所有该 interface 的函数。对于那些显式实现 interface 的语言来说,对于 IDE 的 interface 实现查找来说就友好多了。另一方面,我们看到一个 struct,也希望能够立刻知道这个 struct 实现了哪些 interface,但也有着和前面提到的相同的问题。 +但这种“正交”性也会给我们带来一些麻烦。当我们接手了一个几十万行的系统时,如果看到定义了很多 interface,例如订单流程的 interface,我们希望能直接找到这些 interface 都被哪些对象实现了。但直到现在,这个简单的需求也就只有 goland 实现了,并且体验尚可。Visual Studio Code 则需要对项目进行全局扫描,来看到底有哪些 struct 实现了该 interface 的全部函数。那些显式实现 interface 的语言,对于 IDE 的 interface 查找来说就友好多了。另一方面,我们看到一个 struct,也希望能够立刻知道这个 struct 实现了哪些 interface,但也有着和前面提到的相同的问题。 -如果我们只是为了规定一个业务组件需要实现哪些功能的话,必须用 interface 么?显然不是必须的: +interface 本身的意义在哪里呢?一是依赖反转,在 Go 的正交 interface 的设计场景下甚至可以去除依赖;二是由编译器来帮助我们在编译期就能检查到类似“未完全实现接口”这样的错误,如果业务未实现某个流程,但又将其实例作为 interface 强行传给我们的初始化函数,就会报出下面的错误: ```go +TODO ``` ## 要不要用继承? +既然谈到了 interface,那就免不了要提到继承的问题。有很多 java 和 C# 来的程序员对于 Go 没有继承非常的不习惯。继承也是为了实现抽象,把复杂模块中的公共逻辑向上抽离至抽象类,以达到代码共用的目的。所以说到面向对象,大多数程序员脑子里第一反应就是:"封装、继承、多态"。封装和多态自不用说,而继承在 Go 里与传统的 OOP 语言里差别非常之大,甚至有人觉得已经差异到了令人发指的程度,比如下面的例子: + +TODO,继承是正确的设计模式么? + ## table-driven 开发 熟悉开源 lint 工具的同学应该见到过圈复杂度的说法,在函数中如果有 if 和 switch 的话,会使函数的圈复杂度上升,所以有强迫症的同学即使在入口一个函数中有 switch,还是想要干掉这个 switch,有没有什么办法呢?当然有,用表驱动的方式来存储我们需要实例: