Samenwerkende objecten · oefening
Houd domeinlogica los van invoer en uitvoer
Elke klasse die je dit hoofdstuk hebt geschreven geeft waarden terug. Geen ervan drukt iets af. Dat was bewust, en het is de moeite waard om te zeggen waarom voordat de eerste klasse die het lijkt nodig te hebben die gewoonte doorbreekt.
Stel dat QuizAttempt.answer behulpzaam was geschreven:
Het werkt en voor een klein script is het erg handig. De kosten komen later, allemaal tegelijk.
Wat het afdrukken kost
Vraag je af wat er gebeurt als het programma groeit:
Testen. Je kunt de score rechtstreeks controleren, maar om de feedback te controleren moet je de standaarduitvoer opvangen.
Een andere interface. Als je deze quiz op een webpagina zet, moet het bericht in HTML verschijnen. De methode drukt af naar een terminal die niet meer bestaat.
Taal. De feedback vertalen betekent dat je de code voor scoreberekening moet aanpassen.
Hergebruik. Opgeslagen pogingen beoordelen om een overzicht te maken, drukt nu ook feedback af waar niemand om heeft gevraagd.
Stilte. Je kunt geen score berekenen zonder iets te zeggen.
Elk hiervan is hetzelfde probleem: een beslissing over presentatie is ingebouwd in een object dat over regels gaat.
De twee scheiden
Het woord voor het regelgedeelte is het domein: vragen, antwoorden, scores, slagen. Die bestaan ongeacht of iemand kijkt. Daaromheen zit de interface: afdrukken, invoer lezen, opmaak, kleuren, HTML.
Houd domeinobjecten stil. Laat ze berekenen, beslissen en teruggeven. Laat het praten aan de rand van het programma gebeuren:
Dezelfde uitvoer. Nu geeft answer een gegeven terug, maakt feedback van een gegeven een zin en zet print een zin op een scherm. Drie taken, drie plekken, en alleen de laatste maakt zich druk om het bestaan van een terminal.
Welke van deze taken hoort in een domeinklasse zoals QuizAttempt?
De vorm die dit aan een programma geeft
Een programma dat zo is opgebouwd heeft lagen, geordend naar hoe vaak ze veranderen:
entry point input(), print(), the loop that drives everything
formatting ScoreReport, feedback(): facts into text
domain Quiz, Question, QuizAttempt, Response: the rules
Afhankelijkheden wijzen naar beneden. De opmaak kent het domein en het domein weet niets over opmaak. Daarom kan dezelfde Quiz een terminalprogramma, een webpagina en een testsuite bedienen zonder het verschil te merken.
Een snelle manier om je eigen code te controleren: als je elke print en input uit het programma verwijderde, zouden de domeinklassen dan nog logisch en testbaar zijn? Zo ja, dan ligt de grens op de juiste plek.
Redelijk blijven
Dit is geen regel die afdrukken altijd verbiedt. Een script van tien regels dat tussendoor afdrukt is prima, en drie lagen toevoegen zou het slechter maken.
Het is ook geen regel dat domeincode nooit iets mag melden. ValueError opgooien, zoals in hoofdstuk 5, is een domeinobject dat een probleem meldt zonder te beslissen hoe het wordt getoond. De aanroeper vangt die op en kiest tussen een rode melding, een logregel of een nieuwe poging. Hoofdstuk 12 bouwt op precies die scheiding voort.
De oefening neemt een werkend quizprogramma waarin afdrukken over de klassen is verspreid en verplaatst de presentatie naar de rand.
Opdracht
De startcode mengt antwoordfeedback met scoreberekening. Verplaats het afdrukken uit QuizAttempt, zodat de domeinklassen in plaats daarvan gegevens teruggeven:
QuizAttempt.answer(question, given)geeft terug of het antwoord juist was.QuizAttempt.scoreencorrect_countblijven properties, enresponses()geeft een kopie van de antwoordmomentopnamen terug.ScoreReport.review_lines()geeft een lijst met strings terug: een kopReview of <quiz title>, dan één regel per antwoord in de geregistreerde volgorde. Elke antwoordregel begint met twee spaties en luidt<prompt> -> <given> (right)of<prompt> -> <given> (wrong).
Druk in run_quiz na elk antwoord het resultaat van de gegeven feedback(question, correct) af, daarna de herhalingsregels en vervolgens het bestaande scoreoverzicht. Alleen run_quiz drukt af; vragen aanmaken, scores berekenen en domeingegevens lezen mogen geen uitvoer produceren.
Het gegeven programma moet dit opleveren:
Correct!
Not quite. The answer was def.
Review of Chapter 5 Review
What does len('cat') return? -> 3 (right)
Which keyword starts a function? -> class (wrong)
Mina: 2 of 5