码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-08-11 23:31:42      阅读:201      评论:0      收藏:0      [点我收藏+]

标签:

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?

No, because everyone would create a Deadly Diamond of Death since all objects implicitly derive from Object.

Ah! I see. And the compiler writers couldn‘t make Object a special case?

Uh... Well, they didn‘t.

Hmmm. I wonder why? Have other compiler writers solved this problem?

Well, C++ allows you to create diamonds.

Yes, and I think Eiffel does to.

And, gosh, I think Ruby figured out a way to do it.

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.

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?

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?

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#.

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++.

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 fromSubject!

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.

Well then just implement the register and notify functions inMyObservableWidget

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?

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.

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

标签:

原文地址:http://blog.csdn.net/zwvista/article/details/47428111

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!