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.

3
  • Possible duplicate of When are Getters and Setters Justified – gnat Feb 21 '19 at 19:58
  • While I digest this, one bit of (hopefully) helpful advice. I recommend you avoid using type as an identifier. The name type already exists implicitly. I've been burned by this a number of times. – JimmyJames Feb 21 '19 at 20:12
  • @JimmyJames - I should have remember that, I'm around Python for most of my day. Good advice! – user327264 Feb 21 '19 at 21:45
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.

7
  • +1 for applicable examples – mmathis Feb 21 '19 at 20:39
  • potion.affect(player); why should potion beware of whose drinking it? Could you elaborate a little more, because I can't see how a potion can effect a player without telling the player how (increase health or mana). I think it would be easier to see a code sample to illustrate what you're explaining. – user327264 Feb 21 '19 at 21:49
  • @EmilyScott I don't yet understand your confusion. The potion is not aware that the player is drinking it, the player is. The potion is aware that it was sent an affect() message with a target. For all the potion knows it was thrown at someone. – candied_orange Feb 21 '19 at 21:57
  • @candied_orange - Ah! I see. I'm still a little confused, because how do I tell the player to increase either health or mana? You have the check the potion to determine that, which means calling the getter for the type. I think it would be better if I see this in code. – user327264 Feb 21 '19 at 22:00
  • @EmilyScott alas I don't have python 3 installed on this workstation. I'm reluctant to post code that I can't test. Can you give me a few hours to get home? – candied_orange Feb 21 '19 at 22:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy