我正在编写某种包含机器人,物品等的棋盘游戏。
有一次,我需要获得机器人的能量值或能够获得能量的物品。编程方式是每个机器人和每个具有能量的项目都有一个EnergyContainer类作为字段(以防止代码冗余)和能量值类。
现在,基本上,我调用一个接收Element的方法evaluate()。元素是机器人和项目扩展的抽象类。并非所有元素都有能量容器。如果可能的话,我需要在这个元素上调用getEnergyContainer,但前提是它是一个包含它的元素。
我可以想到几个解决方案:使用大量的instanceOf然后再进行转换。因此,例如,如果元素是instanceof robot,则将元素转换为robot并在元素上调用getEnergyContainer。这有明显的缺点,我需要为每个具有元素子类的能量做这个。
第二个解决方案是定义一个只包含getEnergyContainer方法的接口,并让所有具有类的能量实现这一点。这个接口的唯一目的是促进一种方法,它几乎是空的。
除非有人有更好的想法,否则什么是“最佳”解决方案?我认为几乎空的接口被用作标记接口,但这只是一个目的,所以我有点倾向于它。答案 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
。
此代码的潜在改进将是引入
hasEnergy()
方法,使您的代码更具可读性,而不是检查值== 0 Element
实现接口
醇>