标记接口 vs 空抽象 class

Marker interface vs empty abstract class

我很难决定是使用 marker interface 还是空摘要 class。

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

void register(Receivable receivable, BrokerObserver observer)

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

在这种情况下,通常更可取的方法是什么?为什么?

编辑 1

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

抽象class 对比标记界面:

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

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

抽象 class 的目的是提供一个适当的超级 class,其他 classes 可以从中继承并因此共享一个共同的设计 - 你的 class es 没有共同的设计,也没有什么可以分享的。此外,您会将它们都固定在一些受限的设计中,如果您将来需要向它们添加一个真正不同的 parents,那么它们将不会那么灵活。

use-cases 的摘要列表 class:

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

  • Class扩展你的摘要的那些class有很多常用的方法或者 字段或需要 public 以外的访问修饰符(例如 受保护和私有)。

  • 声明 non-static 或 non-final 字段使您能够定义 可以访问和修改 object 状态的方法 他们属于。

Use-cases 接口:

  • 不相关的 class 将实现您的界面。

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

  • 多重继承的优势

所有列出的参数都是针对接口的使用。由于 BrokerResponse 本身是抽象的并且有自己的层次结构,这使得那些 class 没有共同点的事实更加强烈。

作为替代方法,您可以使用标记注释。我会考虑采用这两种方法中的一种而不是 Abstract Class.

标记界面与标记注释:

根据 Joshua Bloch 的“有效 java”:

Marker interfaces have two advantages over marker annotations. First and foremost, marker interfaces define a type that is implemented by instances of the marked class; marker annotations do not. The existence of this type allows you to catch errors at compile time that you couldn’t catch until runtime if you used a marker annotation. Another advantage of marker interfaces over marker annotations is that they can be targeted more precisely.

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

you must use an annotation if the marker applies to any program element other than a class or interface, as only classes and interfaces can be made to implement or extend an interface.

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

Ask yourself the question, Might I want to write one or more methods that accept only objects that have this marking? If so, you should use a marker interface in preference to an annotation. This will make it possible for you to use the interface as a parameter type for the methods in question, which will result in the very real benefit of compile-time type checking.

总结:

If you want to define a type that does not have any new methods associated with it, a marker interface is the way to go.

If you want to mark program elements other than classes and interfaces, to allow for the possibility of adding more information to the marker in the future, or to fit the marker into a framework that already makes heavy use of annotation types, then a marker annotation is the correct choice.

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

想象一下你的 class 已经被标记为 Subscribable 的情况,例如也应该是 Writable。如果您使用空摘要 class,您将需要重新设计整个层次结构。使用标记接口就像将 Writable 添加到实现列表一样简单。

注释它们怎么样?您得到的答案是,如果您必须选择,使用标记接口是前往此处的方式,但是根据您可能需要执行的操作使用注释会更清晰。

您说您需要以某种方式制作它们的事实 "the same" 谈到 instanceof 调用并在此基础上做一些事情。同样的事情可以通过 isAnnotationPresent 或类似的方式实现。

但是如果你添加一个标记接口,如何让它不是一个标记接口 - 只有在你有有限数量的类你需要测试的情况下反对?类似于 MyInterface {boolean isSubscribable();}