'Interface' Considered Harmful -- 接口被认为是有害的

What do you think of interfaces?
对于接口,你怎么看?

You mean a Java or C# interface?
你是说Java或者C#的接口吗?

Yes, are interfaces a good language feature?
是的,接口是一种不错的语言特性吗?

Of course, they're great!
当然了,接口非常棒!

Really. Hmmm. What is an interface? Is it a class?
是吗。那什么是接口?接口是类吗?

No, it's different from a class.
不是,接口和类有区别。

In what way?
在哪方面有区别?

None of it's methods are implemented.
接口中没有一个方法有具体实现。

Then is this an interface?
那这个是接口吗?

public abstract class MyInterface {
  public abstract void f();
}

No, that's an abstract class.
不是,这是一个抽象类。

What is the difference?
有什么区别?

Well, an abstract class can have functions that are implemented.
抽象类中的函数可以有具体实现。

Yes, but this one doesn't. So why isn't it an interface?
是的,不过这个抽象类并没有(包含有具体实现的函数)。为什么它不是接口呢?

Well, an abstract class can have non-static variables, and an interface can't.
抽象类可以有非静态变量,而接口不可以有。

Yes, but this one doesn't. So, again, why isn't it an interface?
是的,不过这个抽象类也没有(包含非静态变量)。还是这个问题,为什么它不是接口呢?

Because it's not.
就因为它不是。

That's not a very satisfying answer. How does it differ from an interface? What can you do with an interface that you cannot do with that class?
这个回答不太能令人满意。这个抽象类和接口究竟有什么区别?什么事你用接口能做到而用这个抽象类做不了?

A class that extends another, cannot also implement your class.
如果一个类已经扩展了另一个类,它就不能实现你这个抽象类了。

Why not?
为什么不行?

Because, in Java, you cannot extend multiple classes.
因为,在Java语言中,你不能扩展多个类。

Why not?
为什么不行呢?

Because the compiler won't allow you to.
因为编译器不允许你这么做。

That's odd. Well, then, why can't I implement that class rather than extend it?
真奇怪。那为什么我就不能实现抽象类而只能扩展它呢?

Because the compiler will only allow you to implement an interface.
因为编译器只允许你实现接口。

My that's a strange rule.
这是一条奇怪的规则。

No, it's perfectly reasonable. The compiler will allow you to implement many interfaces but only allow you to extend one class.
不是,这条规则完全合理。编译器允许你实现多个接口,但它只允许你扩展一个类。

Why do you suppose the Java compiler will allow you to implement multiple interfaces, but won't allow you to extend multiple classes?
为什么你认定Java编译器只允许你实现多个接口而不允许你扩展多个类呢?

Because multiple inheritance of classes is dangerous.
因为类的多重继承有危险性。

Really? How so?
真的吗?怎么会这样呢?

Because of the "Deadly Diamond of Death"!
因为存在致命的死亡钻石问题。

My goodness, that sounds scary. Just what is the Deadly Diamond of Death?
我的天,听起来挺慎人的。那什么是致命的死亡钻石问题呢?

That's when a class extends two other classes, both of which extend yet another class.
那个问题是说一个类扩展两个其他的类,而那两个类又都扩展另外一个类。

You mean like this:
你的意思是不是这样:

class B {}
class D1 extends B {}   
class D2 extends B {}   
class M extends D1, D2 {}

Yes! That's bad!
是的,这种情况很糟糕!

Why is that bad?
为什么这种情况很糟糕?

Because class B might have an instance variable!
因为B类可能会有实例变量。

You mean like this?
你是这个意思吗?

class B {private int i;}

Yes! And then how many i variables would be in an instance of M?
是的!你说一个M的实例会包含多少个i变量呢?

Ah, I see. Since both D1 and D2 have an i variable, and since M derives from both D1and D2, then you might expect M to have two separate i variables.
啊,我明白了。D1和D2都有一个i变量,而M又同时派生自D1和D2,那么你可能会认为M有两个单独的i变量。

Yes! But since M derives from B which has only one i variable, you might expect M to have just one i variable too.

是的。不过既然M也派生自只有一个i变量的B,你可能会认为M也只有一个i变量。

Ah, so it's ambiguous.
所以说有歧义。

Yes!
是的。

So Java (and therefore C#) cannot extend multiple classes because someone might create a Deadly Diamond of Death?
所以说Java(也因此C#)不能扩展多个类是因为有人可能会制造致命的死亡钻石问题吗?

No, because everyone would create a Deadly Diamond of Death since all objects implicitly derive from Object.
不是。原因在于每个人都会制造致命的死亡钻石问题。因为所有的对象都派生自Object类。

Ah! I see. And the compiler writers couldn't make Object a special case?
哦,我明白了。编译器作者难道不能将Object类当做一个特例吗?

Uh... Well, they didn't.
他们没有这么做。

Hmmm. I wonder why? Have other compiler writers solved this problem?
让我想想为什么。其他的编译器作者有没有解决这个问题呢?

Well, C++ allows you to create diamonds.

C++允许你实现钻石继承。

Yes, and I think Eiffel does to.
是的,我想Eiffel语言也行。

And, gosh, I think Ruby figured out a way to do it.
啊,我想Ruby语言也找到了解决办法。

Yes, and so did CLOS and -- well, let's just say that the deadly diamond of death is a problem that was solved decades ago and it isn't deadly, and does not lead to death.
是的,CLOS语言也做到了。也就是说致命的死亡钻石问题是个几十年前就早已解决的问题。这个问题不致命,也不会导致死亡。

Hmmm. Yeah, I guess that's true.
是的,我想这是真的。

So then back to my original question. Why isn't this an interface?
那么回到我原来的问题。为什么这个抽象类就不是接口呢?

public abstract class MyInterface {
  public abstract void f();
}

Because it uses the keyword class; and the language won't allow you to multiply inherit classes.
因为它使用了类这个关键字,而这个语言不允许你扩展多个类。

That's right. And so the keyword interface was invented as a way to prevent multiple inheritance of classes.
没错。所以说发明接口这个关键字是一种避免类的多重继承的办法。

Yeah, that's probably true.
是啊,这很可能是事实。

So why didn't the authors of Java (and by extension C#) use one of the known solutions to implement multiple inheritance?
那为什么Java的设计者(连带C#的设计者)就没有利用已知的解决方案来实现多重继承呢?

I don't know.
我不知道。

I don't know either, but I can guess.
我也不知道,不过我可以猜。

What's your guess?
你猜是什么原因?

Laziness.
懒惰。

Laziness?
懒惰吗?

Yeah, they didn't want to deal with the issue. So they created a new feature that allowed them to sidestep it. That feature was the interface.
是的,他们不想处理这个问题。所以他们创造了一个新的语言特性来绕过它。那个语言特性就是接口。

You are suggesting that the interface feature of Java was a hack that the authors used in order to avoid some work?
你是在暗示Java语言中的接口特性是语言设计者们为了少干活而制定的特殊规则吗?

I can't explain it any other way.
我无法做出其他解释。

Well I think that's kind of rude. I'm sure their intentions were better than that. And anyway it's kind of nice to have interfaces isn't it? I mean, what harm do they do?
我想你这么说很不客气。我确信他们的本意不该如此。不管怎么说有接口挺不错。我的意思是,接口有什么害处吗?

Ask yourself this question: Why should a class have to know that it is implementing an interface? Isn't that precisely the kind of thing you are supposed to hide?
问你自己一个问题:为什么一个类必须知道自己在实现一个接口呢?难道这不正是你应当隐藏的信息吗?

You mean a derivative has to know in order to use the right keyword, extends or implements, right?
你是说派生类不得不使用正确的关键字,扩展还是实现,对吗?

Right! And if you change a class to an interface, how many derivatives have to be modified?
正确!如果你想把一个类变成接口,有多少派生类需要修改?

All of them. At least in Java. They solved that problem in C#.
所有派生类都需要修改。至少在Java语言中是这样。在C#语言中这个问题得到了解决。

Indeed they did. The implements and extends keywords are redundant and damaging. Java would have been better off using the colon solution of C# and C++.
确实解决了。实现和扩展这两个关键字不仅重复而且有害。如果使用C#和C++的冒号方案的话,Java语言本来可以做得更好。

OK, OK, but when do you really need multiple inheritance?
是的,是的,不过到底什么时候你需要多重继承呢?

So, here is what I would like to do:
这是我想做的事:

public class Subject {
    private List<Observer> observers = new ArrayList<>();
    private void register(Observer o) {
        observers.add(o);
    }
    private void notify() {
        for (Observer o : observers)
            o.update();
    }
}

public class MyWidget {...}

public class MyObservableWidget extends MyWidget, Subject {
    ...
}

Ah, that's the Observer pattern!
这是观察者模式啊!

Yes. That's the Observer pattern -- done correctly.
是的,这才是观察者模式被正确实现的方式。

But it won't compile because you can't extend more than one class.
但是这个程序无法通过编译因为你无法扩展一个以上的类。

Yes, and that's a tragedy.
是的,这是个悲剧。

A tragedy? But why? I mean you could just derive MyWidget from Subject!
悲剧吗?为什么?我想你可以简单地让MyWidget从Subject中派生。

But I don't want MyWidget to know anything about being observed. I want to maintain the separation of concerns. The concern of being observed is separate from the concern of widgets.
但是我不想让MyWidget知道任何关于它被观察的事情。我想遵循关注点分离原则。被观察和Widget这两个关注点应当分开。

Well then just implement the register and notify functions in MyObservableWidget
那就在MyObservableWidget类里面实现register和notify函数。

What? And duplicate that code for every observed class? I don't think so!
什么?然后在每个被观察者类里面重复代码吗?我可不想这么做!

Well then have MyObservableWidget hold a reference to Subject and delegate to it?
那就让MyObservableWidget类包含一个指向Subject的引用,然后(把register和notify)委托给它,怎么样?

What? And duplicate the delegation code in every one of my observers? How crass. How degenerate. Ugh.
什么?然后在每个观察者类里面都重复委托的代码吗?太蠢,太差了。

Well, you're going to have to do one or the other of those things.
这些事你不得不选择做其中的一件。

I know. And I hate it.
我知道。但我不喜欢。

Yeah, it seems that there's no escape. Either you'll have to violate the separation of concerns, or you'll have to duplicate code.
是啊,看来也没有别的办法。你要么违反关注点分离原则,要么就重复代码。

Yes. And it's the language forcing me into that situation.
是的,是这种语言迫使我进入这种境地。

Yes, that's unfortunate.
是的,很不幸。

And what feature of the language is forcing me into this bad situation?
那是什么语言特性让我处于这种糟糕的境地呢?

The interface keyword.
是接口关键字。

And so...?
也就是说?

The interface keyword is harmful.
接口关键字是有害的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值