2

我正在用 Java 构建一个简单的游戏。我有几个课程,我省略了与我的问题无关的字段:

public class Character {
    //stores relics and artifacts
    public Set<Collectable> inventory;

    public void collect(Collectable collectable) {
        collectable.collect(this);
    }
}

public class Artifact extends Collectable {
    @Override
    public void collect(Character character) {
        character.inventory.add(this);
    }
}

public class Relic extends Collectable {
    @Override
    public void collect(Character character) {
        character.inventory.add(this);
    }
}

public class Spell extends Collectable {
    @Override
    public void collect(Character character) {
        Wizard wizard = (Wizard) character;
        wizard.spellBook.add(this);
    }
}

public class Wizard extends Character {
    //stores spells
    public Set<Collectable> spellBook;
}

public class Warrior extends Character {
    //fields and methods ommited
}

到目前为止,当我收集法术时,它必须进入巫师的法术书。战士不能收集法术,他们没有法术书。如果我从 OOP POV 中正确理解,Collectable 必须能够在收集时决定它的去向(库存或法术书),因此我在上面的解决方案。

我的问题是我必须在 Spell.collect(Character) 中使用类型转换才能将 Spell 放入向导的 spellBook,因为默认情况下,spellBook 在 Character 上不可见,我认为它不应该是,因为那时战士也会有法术书。这违背了开闭原则,因为如果我想添加一个也可以收集法术的术士,我必须修改法术以尝试将它也施放给术士。

您能否建议一个解决方案或设计模式,以便我可以在不违反开闭原则的情况下收集我的收藏品?

4

3 回答 3

1

考虑到这一点很有趣。这里的其他答案肯定已经解决了您的问题,但我认为在您需要将架构更改为 MVC(模型视图控制器)或 SAM(状态动作模型)之类的东西的宏伟计划中。这些将使您更好地了解如何组成类,b/c 现在似乎您正在尝试根据物理对象来建模您的世界,这不是 OOP 的意义所在。OOP 是关于数据传输的。

使用 MVC,它可能看起来像:

模型:

public class Spell extends MagicCollectable {
    // attributes like damage or healing
}

public class Relic extends PhysicalCollectable {
    // attributes 
}

public class Wizard extends Character {
    //stores spells
    public Set<Collectable> spellBook;
}

public class Warrior extends Character {
    //fields and methods ommited
}

控制器:

public class WizardController {
    private Wizard wizard;
    public void collect(MagicCollectable collectable);
}

public class WarriorController {
    private Warrior warrior;
    public void collect(PhysicalCollectable collectable);
}

所以在你的游戏循环中,你实际上会实例化 WizardController 来体现你的角色。另请注意,与其他答案一样,我正在创建更具体的模型。

于 2021-11-06T17:17:25.453 回答
0

没有理由public Set<Collectable> spellBook;不应该public Set<Spell> spellBook;

最好的办法是制作一个接口:

interface SpellCaster{
    void addSpell();
    //other methods
}

并使任何应该能够收集法术的角色都实现这个接口。

编辑:然后 Spell 中的 collect 方法应如下所示:

@Override
public void collect(SpellCaster character) {
    character.addSpell(this);
}

尽管您可能应该重命名该方法。您有两个收集方法正在做一些完全不同的事情。

于 2021-11-06T16:37:34.793 回答
0

我觉得有趣的是,你决定让收藏品决定它的去向。在现实世界的场景中,角色不会收集收藏品,例如巫师收集咒语吗?

public class Wizard extends Character {
    //stores spells
    private Set<Spell> spellBook;

    public void addSpell(Spell spell) {
        spellBook.add(spell);
    }
}
于 2021-11-06T16:49:51.120 回答