不同意 #14 的说法,实际上 #14 所需要的只是 Composable 的 interface ,而并不是所谓的 duck typing 。
引用原文:
> - Don't implement Interfaces preemptively.
在这里提到的 case 实际上是因为,Java 由于无法对任意 External Type 实现 Internal interface ,所以如果原始的行为 Contract 没有被声明为 Interface ,我们既不能实现我们自己的替代品(有 interface 的情况下,实现一个 Adapter 不就可以了?),也无法使用我们的 interface 去将其替代;而这个限制在 Rust 中已经被放宽到不允许使用 External struct 去实现 External trait (
https://doc.rust-lang.org/book/ch10-02-traits.html#implementing-a-trait-on-a-type )。
而 Go 这种 Duck typing ,实际上比起 Java 的显式声明,是另一种推卸责任。举个例子,假定我存在两个 interface:
```go
type Visitor interface {
Saw() bool // If we have seen this node
}
type Sawyer interface {
Saw() bool // Can sawyer saw?
}
```
当我实现 `func (???) Saw() bool` 的时候,我究竟在实现谁?这大大加剧了误用几率,反而在工程上是一个 bad practice 。(这种 case 一定存在,参考 Hyrum's Law -
https://www.hyrumslaw.com/ ,一个行为只要被足够多的人观察,无论是否跟你的设计和想法保持一致,一定会有人在依赖这个行为)。
如何回避上述行为?一种方案是实现一个空的 method ,限定其在特定 namespace 下面,比如:
```go
type Visitor interface {
Saw() bool
IsVisitorImpl()
}
// ...
```
但这跟 Java 的 `implements XXX` 相比,无非是把这个 Tag 下推到 `interface` 内部了,本质是完全一样的。
而如果实现细粒度的 `interface`,#40 提出了一个很好的例子,我们甚至可以:
```java
public interface Putter {
String put(Item item);
}
public interface Getter {
Item get(String key);
}
public class Storage {
private Putter putter;
private Getter getter;
}
```
虽然有点累赘,一样实现了类似的细粒度接口组合,并未有任何功能上的差异。