假设我正在用Java建模不同的动物。每只动物都有这些能力的组合:散步,游泳和飞翔。例如,能力集是不变的。
我可以将此信息存储为返回常量的getter。例如:
public class Penguin implements Animal {
public boolean canWalk() {
return true;
}
public boolean canSwim() {
return true;
}
public boolean canFly() {
return false;
}
// implementation...
}
然后运行时检查:
if (animal.canFly()) {
// Fly!
}
或者我可以使用"标记"接口:
public class Penguin implements Animal, Flyer, Swimmer {
// implementation...
}
然后运行时检查:
if (animal instanceof Flyer) {
// Fly!
}
每种方法有哪些优缺点?
答案 0 :(得分:5)
标记接口在现代Java中是一种反模式,在早期需要,因为无法直接向类添加元数据。 “现代”方法是注释:
read
运行时检查:
@Retention(RetentionPolicy.RUNTIME)
@interface Flyer {
}
@Retention(RetentionPolicy.RUNTIME)
@interface Swimmer {
}
@Flyer @Swimmer
public class Penguin implements Animal {
}
如果您想知道的是if(Animal.class.isAnnotationPresent(Flyer.class)) {
// fly!
}
是否具有此特征,那么您可以使用此方法,即航班和游泳功能是纯元数据。
你想要达到什么目的?我不会称之为OOP,因为OOP方法通常不是查询功能和执行特定于对象的条件逻辑,而是使用多态。
答案 1 :(得分:2)
步行/游泳/飞行能力与种类或状态有关吗?这是类标记(种类)和属性(状态)之间的真正区别。
你必须注意,一旦标记了一个类,就永远不能“无标记”。所有子类都将继承它。同样适用于单个实例,因为它无法动态更改其类型(至少在Java中)。
另一个评论与抽象有关。标记需要其他API来了解您的标记类型(接口,类或注释)。而某些API只需要依赖“抽象接口”(即方法名称)。 JavaBean-convention感知API就是这样的例子。并且比编写特定方法更容易集成,以检查类继承或注释存在。
总而言之,静态功能(如Runnable
命令)可以依赖于类标记,其中动态的必须依赖于状态。