1

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

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

现在,基本上,我调用一个接收元素的方法评估()。元素是机器人和物品扩展的抽象类。并非所有元素都有能量容器。如果可能的话,我需要在这个元素上调用 getEnergyContainer,但前提是它当然是一个拥有它的元素。

我可以想到几个解决方案:使用大量 instanceOf 然后进行强制转换。例如,如果元素是 instanceof 机器人,则将元素转换为机器人并在元素上调用 getEnergyContainer。这有一个明显的缺点,我需要对每个具有元素子类的能量执行此操作。

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

除非有人有更好的主意,否则“最佳”解决方案是什么?我认为几乎空的接口被用作标记接口,但这是唯一的目的,所以我有点反对它。

4

3 回答 3

1

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

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

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

毫无疑问,有人会争辩说这在某种意义上是“不纯的”——但几乎可以肯定它比大多数替代方案更简单。

于 2012-05-22T15:40:09.077 回答
1

最好的解决方案是将getEnergyContainer()方法放在所有包含能量的元素的超类之一中,并在每个元素类中覆盖此方法。您可以制作此方法abstract以确保其被覆盖。你的超类可能是Element因为你说:Element is an abstract class which robot and items extend.

于 2012-05-22T15:41:07.467 回答
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. 用于创建各种 EnergyContainer 变体的 AbstractFactory 模式
  2. 包括一种hasEnergy()使您的代码更具可读性而不是检查值 == 0 的方法
  3. Element如果其他类似的父类将包含类似的方法,请实现一个接口
于 2012-05-22T17:00:03.830 回答