Sprint 7 ยท Methodes & self  ยท  US4: Beslissende methodes

Als developer, wil ik dat een methode zelf ongeldige aanroepen weigert en vragen kan beantwoorden met True of False, zodat de data van een object nooit in een onmogelijke toestand komt.

Taak 3: Guard en query samen

Een methode kan eerst vragen stellen en dan pas iets doen. Je bouwt een methode die een bedrag van de ene rekening naar de andere overmaakt, met queries als bewakers.

Vragen, beslissen, doen

De sterkste methodes combineren beide. Ze vragen eerst (query), beslissen dan (guard) en doen daarna pas iets (verandering).

class Tank:
    def __init__(self, capacity):
        self.capacity = capacity
        self.level = 0

    def fill(self, amount):
        if amount <= 0 or self.level + amount > self.capacity:
            return False
        self.level += amount
        return True

    def can_give(self, amount):                 # query
        return amount > 0 and amount <= self.level

    def can_fit(self, amount):                  # query
        return self.level + amount <= self.capacity

    def transfer_to(self, other, amount):       # guard + verandering
        if not self.can_give(amount):
            return False
        if not other.can_fit(amount):
            return False
        self.level -= amount
        other.level += amount
        return True

transfer_to bevat zelf geen rekenwerk voor de regels. Hij vraagt het aan de twee tanks. Verandert er later een regel, dan pas je hem op รฉรฉn plek aan.

Alles of niets. Geeft รฉรฉn van de twee vragen "nee"? Dan verandert er in geen van de twee tanks iets. Er is nooit water weg zonder dat het ergens anders bij is gekomen.

Zie het overpompen

>>> Oefenomgeving: Python REPL Simulator

Pomp water van de ene tank naar de andere en probeer het te laten mislukken.

  1. a = Tank(100)
  2. b = Tank(100)
  3. a.fill(80) โ€” vul a.
  4. a.transfer_to(b, 50) โ€” lukt dit?
  5. a.level
  6. b.level
  7. a.transfer_to(b, 50) โ€” en nog een keer?
  8. a.level โ€” is er iets veranderd?
  9. b.level
Python 3.11 REPL Simulator ยท typ een commando en druk op Enter. # class Tank: # can_give(n) n > 0 en n <= level # can_fit(n) level + n <= capacity # transfer_to(other, n) controleert eerst, verandert daarna
>>> 
๐Ÿงฉ

Jouw opdracht: BankAccount.transfer(other, amount)

Je bankrekening kan nu geld overmaken naar een andere rekening. Je gebruikt je eigen queries als bewakers.

  1. Neem je BankAccount uit taak 2 over, met deposit, withdraw, can_afford en is_empty.
  2. Schrijf transfer(self, other, amount). Weiger een bedrag van nul of minder. Weiger ook als self.can_afford(amount) False geeft.
  3. Is alles in orde? Haal dan het bedrag van deze rekening af en zet het op other. Gebruik daarvoor je eigen methodes withdraw en deposit.
  4. De methode geeft True terug bij gelukt en False bij geweigerd. Bij weigeren verandert geen van beide saldo's.
  5. Maak sam = BankAccount("Sam", 100) en kim = BankAccount("Kim", 20). Maak 50 over van Sam naar Kim en daarna 500. Print na beide pogingen het antwoord en beide saldo's.

Acceptatiecriteria

  • Na sam.transfer(kim, 50) geeft de methode True, Sam heeft 50 en Kim heeft 70.
  • Na sam.transfer(kim, 500) geeft de methode False en de saldo's zijn nog 50 en 70.
  • transfer roept self.can_afford, withdraw en deposit aan; de regels staan niet dubbel in de methode.
  • Het totaal van beide saldo's is na elke aanroep gelijk aan het totaal ervoor.