samedi 6 novembre 2021

Design pattern to avoid violating Open-Closed principle

I'm building a simple game in Java. I have a couple of classes, I omitted the fields that are not relevant to my problem:

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
}

As of right now when I'm collecting a Spell, it has to go into a Wizard's spellBook. Warriors can't collect Spells, they don't have a spellBook. If I understand correctly from an OOP POV, a Collectable has to be able to decide where it goes (inventory or spellbook) when it's collected, hence my solution above.

My problem is that I have to use typecasting in Spell.collect(Character) to be able to put the Spell into a Wizard's spellBook, because by default, spellBook is not visible on Character, and I think it shouldn't be, because then Warriors would have spellBooks aswell. This goes against the Open-Closed principle, since if I wanted to add a Warlock, who can also collect Spells, I would have to modify Spell to try and cast it to Warlock aswell.

Could you please suggest a solution or design pattern, so that I can collect my Collectables without violating the Open-Closed princible?

Aucun commentaire:

Enregistrer un commentaire