铸造和实例或接近空的界面?

时间:2012-05-22 15:36:03

标签: java interface instanceof

我正在编写某种包含机器人,物品等的棋盘游戏。

有一次,我需要获得机器人的能量值或能够获得能量的物品。编程方式是每个机器人和每个具有能量的项目都有一个EnergyContainer类作为字段(以防止代码冗余)和能量值类。

现在,基本上,我调用一个接收Element的方法evaluate()。元素是机器人和项目扩展的抽象类。并非所有元素都有能量容器。如果可能的话,我需要在这个元素上调用getEnergyContainer,但前提是它是一个包含它的元素。

我可以想到几个解决方案:使用大量的instanceOf然后再进行转换。因此,例如,如果元素是instanceof robot,则将元素转换为robot并在元素上调用getEnergyContainer。这有明显的缺点,我需要为每个具有元素子类的能量做这个。

第二个解决方案是定义一个只包含getEnergyContainer方法的接口,并让所有具有类的能量实现这一点。这个接口的唯一目的是促进一种方法,它几乎是空的。

除非有人有更好的想法,否则什么是“最佳”解决方案?我认为几乎空的接口被用作标记接口,但这只是一个目的,所以我有点倾向于它。

3 个答案:

答案 0 :(得分:1)

  

如果可能的话,我需要在这个元素上调用getEnergyContainer,但前提是它是一个包含它的元素。

为什么你不想在没有能量容器的元素上调用它?如果 没有能量容器,则返回对EnergyContainer的某个“空对象”实现的引用,或返回空引用。这取决于你以后想要做什么 - 如果你可以轻松实现某种“中性”能量容器,那么空对象模式是最简单的方法。否则,只需:

EnergyContainer container = element.getEnergyContainer();
if (container != null) {
    // Use the container
}

毫无疑问,那些会认为这在某些意义上“不纯”的人 - 但它几乎肯定比其他大多数人更简单。

答案 1 :(得分:1)

最好的解决方案是将getEnergyContainer()方法放在所有包含元素的超类之一中,在每个元素类中重写此方法。您可以使用此方法abstract来确保其过度使用。你的超级班级可能是Element,因为你说:Element is an abstract class which robot and items extend.

答案 2 :(得分:0)

鉴于您的类层次结构使用带有接口的合成来提供默认的EnergyContainer行为

abstract class Element {

    EnergyContainer ec = new EmptyEnergyContainer();

    int getEnergyValue() {
        getEnergyContainer().getValue();
    }

    EnergyContainer getEnergyContainer() {
        return ec;
    }

    setEnergyContainer(EnergyContainer container) {
        this.ec = container;
    }
}

class Robot extends Element {

    public Robot() {
        this.ec = new ActiveEnergyContainer();
    }
}

class Item extends Element{

    public Item() {
        this.ec = new ActiveEnergyContainer();
    }
}

class Brick extends Element{
    // will have a EmptyEnergyContainer by default
}

EnergyContainer的接口层次结构就像这样

interface EnergyContainer {
    int getValue();
    setValue(int value);
}

class EmptyEnergyContainer implements EnergyContainer {
    @Override
    int getValue() {
        return 0;
    }

    @Override
    setValue(int val) {
        throw Exception("Can not charge an empty container");
    }
}

class ActiveEnergyContainer implements EnergyContainer {
    int value;

    @Override
    int getValue() {
        return 17 + 3;  // calculate the value
    }

    @Override
    setValue(int val) {
        this.value = val // or do some funky calculation
    }
}

在运行时,您可以为对象设置新的EnergyContainer类型。如果您有多个父类,如Element,那么您将必须遵循相同的模式,将默认行为添加到抽象父级并根据需要覆盖。

让默认行为为getValue()返回合理的默认值将帮助您不必在整个地方使用instanceof

此代码的潜在改进将是引入

  1. AbstractFactory模式,用于创建各种EnergyContainer 变体
  2. 包含hasEnergy()方法,使您的代码更具可读性,而不是检查值== 0
  3. 如果其他类似的父类将包含模拟方法
  4. ,则使Element实现接口