避免抽象静态方法(或覆盖静态方法)的设计模式

时间:2013-12-30 10:59:20

标签: java oop design-patterns static-methods abstract

我知道静态方法不能是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(),它知道它实例化的法术的最大力量属性。然而,这对我来说似乎并不是最佳的,因为:

  1. 每个法术更有意义了解自己的属性
  2. 这使得Spell的子类无视实现细节(即,它的构造函数无法检查提供的功率是否超过其最大功率)
  3. 工厂模式是否正确?如果是这样,它的逻辑理由是什么?如果没有,是否有更适合这个问题的模式?

3 个答案:

答案 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()转换为工厂方法。在幕后,它实例化自身的实例,缓存它并查询实例。