我知道静态方法不能是abstracted,也不能被覆盖only hidden (and in which case late bindings don't happen)。关于这一点,我正在努力用一种合乎逻辑的方式来表达以下关系:
public abstract class Spell {
protected int power;
public Spell(int power) {
this.power = power;
}
public int getPower() { return power; }
// I know this is impossible, but please bare with me
public abstract static int getMaxPower();
}
public class AttackSpell extends Spell {
public AttackSpell(int power) {
super(power);
}
public static int getMaxPower() { return 50; }
}
public class HealSpell extends Spell {
public HealSpell(int power) {
super(power);
}
public static int getMaxPower() { return 30; }
}
在这个人为的例子中,最大功率是我希望每个法术都知道的属性(Spell
的每个子类都有一个适用于其自身所有实例的单独最大功率)。在其他SO线程中,针对这种不可能情况的建议解决方案是使getMaxPower()
成为实例方法。但是,我不认为这是有道理的,因为幂是一个实例细节,在实例化之前有用(例如,构造一个从幂1到该法术最大幂的法术实例数组)。
我看到的一个解决方案是为每个法术创造一个工厂(或者对于所有法术更为通用),它有一个实例方法getMaxPower()
,它知道它实例化的法术的最大力量属性。然而,这对我来说似乎并不是最佳的,因为:
工厂模式是否正确?如果是这样,它的逻辑理由是什么?如果没有,是否有更适合这个问题的模式?
答案 0 :(得分:3)
从法术中断开生成法术将是我的第一个想法。
有一个类描述了具有力量范围的咒语族,然后用它来创建范围内的法术集合,通过构造函数传递力量等。
然后你可以考虑某种数据文件,为你节省大量的硬编码。
答案 1 :(得分:1)
由于您只能覆盖非静态函数,我只看到一种方法:您必须以某种方式将信息附加到Class
对象。
但这不是设计模式,我知道......
您最好用信息注释您的班级并使用反射。由于注释可以继承,因此这应该是您想要的行为。有关如何使用它的示例,请参阅拼写中的main
。
注释类型的定义:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface SpellInfo {
int maxPower();
}
注意:Integer.MIN_VALUE
是“未定义”的值。
@SpellInfo(maxPower = Integer.MIN_VALUE)
public class Spell {
protected int power;
public Spell(int power) {
this.power = power;
}
public int getPower() { return power; }
public static int getMaxPower(Class<? extends Spell> c) {
return c.getAnnotation(SpellInfo.class).maxPower();
}
public final int getMaxPower() {
return getMaxPower(this.getClass());
}
// test it
public static void main(String[] args) {
System.out.println("Spell.getMaxPower(Spell.class)="+
Spell.getMaxPower(Spell.class));
System.out.println("Spell.getMaxPower(AbstractSpellType.class)="+
Spell.getMaxPower(AbstractSpellType.class));
System.out.println("Spell.getMaxPower(HealingSpell.class)="+
Spell.getMaxPower(HealingSpell.class));
System.out.println("Spell.getMaxPower(AttackSpell.class)="+
Spell.getMaxPower(AttackSpell.class));
Spell spell = new AttackSpell(3);
System.out.println("((Spell) new AttackSpell(3)).getMaxPower()=" +
spell.getMaxPower());
spell = new HealingSpell(4);
System.out.println("((Spell) new HealingSpell(4)).getMaxPower()=" +
spell.getMaxPower());
}
}
AbstractSpellType从Spell
继承注释public abstract class AbstractSpellType extends Spell {
public AbstractSpellType(int power) {
super(power);
}
}
@SpellInfo(maxPower = 30)
public class HealingSpell extends Spell {
public HealingSpell(int power) {
super(power);
}
}
@SpellInfo(maxPower = 50)
public class AttackSpell extends Spell {
public AttackSpell(int power) {
super(power);
}
}
答案 2 :(得分:0)
一种简单的方法是将getMaxPower()
转换为工厂方法。在幕后,它实例化自身的实例,缓存它并查询实例。