11

我在使用标记接口或空抽象类之间做出决定时遇到了困难。

我有两个类BrokerResponseNotification,它们没有结构相似性。唯一连接它们的是需要订阅。

void register(Receivable receivable, BrokerObserver observer)

我不知何故不喜欢使用 a Marker Interface,因为它违反了 a 的基本定义Interface。另一方面,使用一个abstract super类会让我感到不舒服,因为这两个类之间没有任何关系。

在这种情况下,通常首选的方法是什么?为什么?

编辑 1

我忘了说,那BrokerResponse是一个抽象类本身,它有几个子类来确定各自的类型。

4

3 回答 3

9

抽象类与标记接口:

标记界面没有任何问题,并且有一些用例。在这两者之间进行选择,标记界面具有更大的灵活性。

如果您确实要定义类型,请使用接口。

抽象类的目的是提供一个适当的超类,其他类可以从该超类继承并共享一个共同的设计——您的类没有共同的设计,也没有什么可共享的。此外,如果您将来需要为它们添加真正不同的父母,您将把它们都坚持一些受限制的设计,并且不会那么灵活。

抽象类的用例列表:

  • 在几个密切相关的类之间共享代码。

  • 扩展您的抽象类的类具有许多公共方法或字段,或者需要公共以外的访问修饰符(例如受保护和私有)。

  • 声明非静态或非最终字段,使您能够定义可以访问和修改它们所属对象状态的方法。

接口用例:

  • 不相关的类将实现您的接口。

  • 指定特定数据类型的行为,而不考虑谁实现其行为。

  • 多重继承的优势。

所有列出的参数都是用于接口的。由于BrokerResponse它本身是抽象的,并且有自己的层次结构,因此这些类没有共同点的事实更加强大。

作为替代方案,您可以使用标记注释。我会考虑坚持这两种方法之一,而不是抽象类。

标记界面与标记注释:

根据 Joshua Bloch 的“ Effective java ”:

与标记注释相比,标记接口有两个优点。首先,标记接口定义了由标记类的实例实现的类型;标记注释没有。如果使用标记注释,这种类型的存在允许您在编译时捕获到运行时才能捕获的错误。标记接口相对于标记注释的另一个优点是可以更精确地定位它们。

什么时候应该使用标记注释?

如果标记适用于类或接口以外的任何程序元素,则必须使用注释,因为只有类和接口才能实现或扩展接口。

什么时候应该使用标记界面?

问自己一个问题,我是否想编写一个或多个只接受具有此标记的对象的方法?如果是这样,您应该优先使用标记界面而不是注释。这将使您可以将接口用作相关方法的参数类型,这将带来编译时类型检查的真正好处。

概括:

如果您想定义一个没有任何新方法与之关联的类型,那么标记接口是可行的方法。

如果您想标记除类和接口之外的程序元素,以允许将来向标记添加更多信息,或者将标记适合已经大量使用注释类型的框架,那么标记注释是正确的选择。

于 2018-04-23T09:32:23.907 回答
2

在这种情况下使用空抽象类没有任何意义,因为Java. 让你的类实现一些标记接口不会改变你的类层次结构,它只是用一些额外的元数据标记你的类。

例如,当您的课程已经被标记为时Subscribable也应该是这样的情况Writable。如果您使用空抽象类,则需要重新设计整个层次结构。使用标记接口,就像添加Writable到实现列表一样容易。

于 2018-04-23T09:41:10.623 回答
2

注释它们怎么样?您得到的答案是,如果您必须选择使用标记接口是这里的方法,但根据您可能需要做的事情使用注释会更干净。

您说您需要以某种方式使它们“相同”的事实是在谈论一个instanceof电话并以此为基础做某事。同样的事情可以通过isAnnotationPresent等来实现。

但是如果你添加一个标记接口,让它不是一个标记接口怎么样——只有在你需要测试的类数量有限的情况下?类似的东西MyInterface {boolean isSubscribable();}

于 2018-04-23T19:06:10.663 回答