在Java中,我应该对常量属性使用getter还是接口标记?

在Java中,我应该对常量属性使用getter还是接口标记?,java,oop,design-patterns,interface,Java,Oop,Design Patterns,Interface,假设我正在用Java为不同的动物建模。每种动物都有这些能力的组合:行走、游泳和飞翔。例如,能力集是常量 我可以将此信息存储为返回常量的getter。例如: public class Penguin implements Animal { public boolean canWalk() { return true; } public boolean canSwim() { return true; } public b

假设我正在用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! 
}
if (animal instanceof Flyer) {

    // Fly! 
}
或者我可以使用“标记”界面:

public class Penguin implements Animal, Flyer, Swimmer {

    // implementation... 
}
运行时检查是:

if (animal.canFly()) {

    // Fly! 
}
if (animal instanceof Flyer) {

    // Fly! 
}

每种方法的优缺点是什么

标记接口在现代Java中有点反模式,在早期是必需的,因为无法直接向类添加元数据。“现代”方法是:

@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方法通常不是查询功能和执行特定于对象的条件逻辑,而是使用多态性。

行走/游泳/飞行功能与种类或状态相关吗?这是类标记(种类)和属性(状态)之间的真正区别

您必须注意,类一旦被标记,就永远不能被“取消标记”。所有子类都将从中继承。这同样适用于单个实例,因为它不能动态更改其类型(至少在Java中是这样)

另一个评论与抽象有关。标记要求其他API了解标记类型(接口、类或注释)。而有些API只需要依赖“抽象接口”(即方法名)。JavaBean感知约定的API就是这样的例子。集成将比编写特定方法来检查类继承或注释的存在更容易


总之,静态功能(如
Runnable
命令)可以依赖于类标记,而动态功能必须依赖于状态。

您需要注释接口的一个参数才能在运行时使用。@Dariusz很好!注释是标记接口的替代品,这是一种常见的误解。有效的Java项目#37:使用标记接口定义类型,特别指出标记接口相对于注释的优势。