4

Suppose I have the following Character, Potion, and PotionType classes:

class Player:

    def __init__(self, name: str, health: int, mana: int):
        self._name = name
        self._attributes: Dict[PotionType,int] = {}
        self._attributes[PotionType.Health] = health
        self._attributes[PotionType.Mana] = mana

    def replenish(self, potion):
        if potion.type in self._attributes:
            self._attributes[potion.type] = potion.amount


class PotionType(Enum):
    Health = 1
    Mana = 2


class Potion:

    def __init__(self, amount : int, type: PotionType):
        self.amount = amount
        self.type = type

    def refill(self, amount):
        pass

My main concern here is the replenish(self, potion) method in the Player class. Is it bad practice for my character object to ask for the potion.type, and potion.amount?

I'm aware of the Tell, Don't Ask guideline, but even the author admits that there is a time and place for getters:

One thing I find troubling about tell-dont-ask is that I've seen it encourage people to become GetterEradicators, seeking to get rid of all query methods. But there are times when objects collaborate effectively by providing information.

and this link:

but I fear that just telling people to avoid getters is a rather blunt tool. There are too many times when objects do need to collaborate by exchanging data, which leads to genuine needs for getters.

Is this one of those situations when there is a genuine need for a getter?

Obviously, a Player will drink the Potion and not exceed the limit, these means sharing the data(type and amount) between the two classes.

1 Answers1

4

When are getters acceptable?

When you are dealing with a collection.

Collections are typically not aware of their contents beyond their address in memory. This not knowing makes them data structures more than traditional objects. I never bemoan them having getters and setters. It's nice to have a place to set a break point.

If you want to follow Tell, don't ask here I wouldn't have the potion reveal it's type or the limit on it's uses. The player doesn't need to know either of those. Following Tell, don't ask the player does need to offer an interface through which the potion can tell the player to do things.

It's typical to think this all has to start with something like this:

player.drink(potion);

And it can. But Tell, don't ask says that should result in:

potion.affect(player);

Which, depending on the potion type, might result in:

player.heal(MAX);

or

player.heal(HALF);

or

player.heal("1d6");

or

player.polymorph(RABID_SQUIRREL);

The whole point of tell, don't ask is it maintains the ability to use polymorphism. The player doesn't have to know what kind of potion this is. The potion doesn't have to understand what the players maximum hit points are, what bonuses to healing the player has, or if the player is immune to rabies. The potion only has to understand what it is trying to tell the player to do. How, or even if, the player does it, is up to the player.

candied_orange
  • 119,268