为什么要使用空的抽象类而不是接口?

6

我使用GWT和Place & Activity机制。

很遗憾,Place是一个类,因此我的自定义Place无法继承另一个类。

当我查看Place代码时,我看到以下内容:

public abstract class Place {

  /**
   * The null place.
   */
  public static final Place NOWHERE = new Place() {
  };

}

看到这个问题,Place可以看作是一个接口。GWT团队选择将Place定义为抽象类而不是接口是否有充分的理由?

总体来说:是否有充分的理由创建真正的空抽象类而不是接口?


接口也可以有常量,因此 NOWHERE 常量不影响它是接口还是抽象类的决定。 - Christoffer Hammarström
@Christopher: 你是对的。我修改了我的帖子。给那位给我点踩的访客:请给我一些提示来改进我的问题,我不明白为什么你要给我点踩。 - Jerome Cance
1
@Martijn Courteaux 可能是破坏行为或心态警察。这在 SO 上是一个常见现象。 - stefan bachert
4个回答

7

一般情况下,我不会定义一个空的抽象类。

但是,如果我未来预期会有一些成员,我可能会决定使用抽象类而不是接口。

“类”表示:这是一个

“接口”表示:这个支持

对于“Place”,我确实可以看到两者都可以,但稍微倾向于使用类。


当你说“expect some members”时,你的意思是“期望某些对象”吗? - Aditya Naidu
@Aditya Naidu 不,我的意思是成员方法或成员字段。 - stefan bachert

5
GWT团队选择将Place定义为抽象类而不是接口,有没有充分的理由呢?我想不出有。但是实际上,在SO上抱怨这个问题是无济于事的。一般来说,与接口相比,创建真正空的抽象类是否有充分的理由呢?假设可以这样做是为了确保未来预期需求的单一公共基类......或者出于其他原因。但总的来说,这是一个不好的主意......我个人的看法是这样的。当然,像这样的事情经常发生是出于历史原因;例如,抽象类可能过去曾有更多成员,现在已被删除。

2
谢谢回答,我并不是在抱怨,只是想理解一下,因为我觉得Gwt团队通常选择很好的设计,而这个设计让我有些困扰。 - Jerome Cance
没有人是完美的。不要担心它。 - Stephen C
1
出于历史原因,+1... 当你不了解历史(以及为满足各种要求而做出的权衡)时,批评设计很容易。 - David

2
我不能确定“地点”(虽然我有一些想法,见下文),但是“活动”已经讨论过了:https://groups.google.com/d/topic/google-web-toolkit-contributors/V8rhZHiXFRk/discussion 就我们所知,Place 在 GWT 中始终是一个抽象类(顺便说一句,NOWHERE 地点是在很久以后添加的;请注意,这个提交引用了一个 Wave - 即将从互联网上消失 - 在那里我们可以看到 interface Place,因此在设计 API 时它曾经是一个接口)。
考虑到在创建PlaceHistoryMapper时使用了PlaceHistoryGenerator(该生成器查看位置层次结构),拥有一个抽象类可以减少许多边缘情况!假设您的PlaceHistoryMapper引用了PlaceTokenizers<Foo>PlaceTokenizer<Bar>,而且您有一个class FooBar implements Foo, Bar {},那么应该使用哪个令牌器?如果您没有在PlaceHistoryMapper中明确引用FooBar类,生成器就无法看到它(或者说不会查看它),因此应该生成什么样的代码呢?请记住,我们都希望确定性,因此生成的代码应始终相同。使用一个类,生成器可以按其继承树的顺序对它们进行排序(从最特定-即派生最多的-到最不具体的),并且可以安全地假定两个位置的类没有特定的继承关系,因此它们可以按任何顺序进行检查(在生成的代码中使用instanceof)并仍提供稳定结果⇒确定性。
免责声明:我是那个报告了排序问题并提供了补丁的人,但是Place已经是一个类了。

谢谢您的回答,这是最清晰、最有理的回答。我认可了它。 - Jerome Cance

0

我不能代表GWT团队说话,但这个抽象类似乎唯一的原因就是强制定义NOWHERE。

正如你发现的那样,在这种方式中使用抽象类会将你强制进入一个可能不适合你业务模型的类层次结构中。因此,总的来说,如果抽象类真的完全为空,那么就没有任何目的。

尤其奇怪的是,这个例子因为接口是一个契约而更加奇怪。GWT的Place没有接口,因此也没有契约。他们的javadoc说明:

“表示应用程序中可作为书签保存的位置”

我本来期望会有一些定义的契约来处理这种情况。一个可作为书签保存的位置需要哪些方法?如果这只是一个标记,像Serializable一样,我肯定会期望它是一个接口而不是一个抽象类。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接