In dit project ga je een escape room software bouwen. We werken modulair: elk van jullie maakt een deelmodule die later geïntegreerd wordt in een groter geheel.
Om dit goed te doen, hebben we duidelijke afspraken nodig over hoe we de software ontwerpen. We werken daarom met architectuurprincipes die ervoor zorgen dat ons programma:
Een 3-lagenarchitectuur verdeelt een programma in drie aparte delen (lagen), elk met een eigen verantwoordelijkheid. Hierdoor wordt je code duidelijk gestructureerd en makkelijker aanpasbaar.
Laag | Rol | Voorbeeld in de escape room |
---|---|---|
Presentation | Verzorgt de interactie met de gebruiker. | Console-interface: invoer van antwoorden, tonen van hints. |
Logic | Bevat de kernlogica en spelregels van het programma. | Puzzels oplossen, hints geven, scores bijhouden. |
Data/Support | Beheert ondersteunende taken zoals data-opslag of timing. | Timer bijhouden, logging van acties. |
🔎 Waarom?
Stel dat je later een grafische interface wilt toevoegen in plaats van een console: met een 3-lagenarchitectuur hoef je alleen de Presentation-laag aan te passen, en blijft de logica hetzelfde.
Bij OOP (objectgeoriënteerd programmeren) ontwerpen we software als een verzameling van objecten. Elk object is een instantie van een klasse en heeft:
Principe | Betekenis | Voorbeeld in ons project |
---|---|---|
Single Responsibility | Elke klasse heeft één taak en doet die goed. | Timer houdt enkel de tijd bij, niet de score. |
High Cohesion | De onderdelen van een klasse werken nauw samen rond die ene taak. | Puzzle heeft alles wat met een puzzel te maken heeft (vraag, oplossing, hints). |
Low Coupling | Klassen zijn zo min mogelijk afhankelijk van elkaar. | Player weet niets over hoe Puzzle werkt, enkel dat er puzzels zijn. |
Een abstracte klasse is een soort blauwdruk voor andere klassen. Ze bepaalt wat er moet zijn, maar niet hoe het werkt. Je kan geen object maken van een abstracte klasse.
from abc import ABC, abstractmethod
class Puzzle(ABC): # Abstracte klasse
@abstractmethod
def check_solution(self, answer: str) -> bool:
"""Controleert of het antwoord juist is."""
pass
@abstractmethod
def get_hint(self) -> str:
"""Geeft een hint voor de puzzel."""
pass
Puzzle
verplicht alle subclasses om de methodes check_solution()
en get_hint()
te implementeren.Puzzle
maken, maar wel van klassen die ervan erven (zoals RiddlePuzzle
of CodeLockPuzzle
).Puzzle
is, zonder te weten welk type.In sommige talen bestaan interfaces als apart concept (bijvoorbeeld in Java). In Python gebruiken we hiervoor meestal abstracte basisklassen (ABC).
Een interface is als een contract: het zegt welke methodes een klasse moet hebben, maar niet hoe ze werken.
class Component(ABC): # Interface
@abstractmethod
def start(self):
"""Start het component."""
pass
@abstractmethod
def stop(self):
"""Stopt het component."""
pass
@abstractmethod
def status(self) -> str:
"""Geeft de status van het component."""
pass
Een klassendiagram is een visuele voorstelling van de structuur van je code: welke klassen er zijn, welke attributen en methoden ze hebben, en hoe ze met elkaar verbonden zijn. Het helpt je nadenken over het ontwerp vóór je begint te coderen.
We gebruiken draw.io (diagrams.net) om je diagrammen te tekenen. Deze tool kan je rechtstreeks aan GitHub koppelen, zodat je je diagrammen veilig in de repository bewaart.
Jullie kiezen één module per persoon. Alle modules bevatten abstracte klassen of interfaces, zodat iedereen deze concepten toepast:
Module | Abstracte klasse / Interface | Concrete klassen (voorbeelden) | Rol |
---|---|---|---|
A: Puzzelsysteem | Puzzle (abstract) |
RiddlePuzzle , CodeLockPuzzle |
Beheert de puzzels die spelers moeten oplossen. |
B: Gebruikersbeheer | User (abstract) |
Player , Admin |
Beheert gebruikers: registratie, voortgang, rollen. |
C: Kerncomponenten | Component (interface) |
Timer , Logger , HintSystem |
Algemene onderdelen die het spel ondersteunen: tijd, logs, hints. |
Bespreek met je klasgenoten wie welke module uitwerkt.
feature/puzzles
(A)feature/users
(B)feature/core-components
(C)puzzles
voor leerling Ausers
voor leerling Bcore
voor leerling Cklassendiagram.drawio
in jouw map (puzzles/
, users/
, core/
).Iedereen ontwerpt een abstracte klasse of interface én minstens twee concrete klassen die hiervan erven. Elk klassendiagram bevat:
puzzles
Abstracte klasse: Puzzle
Concrete klassen: RidldlePuzzle
en CodeLockPuzzle
Stap-voor-stap hulp:
users
Abstracte klasse: User
Concrete klassen: Player
en Admin
Stap-voor-stap hulp:
core
Interface (abstracte klasse): Component
Concrete klassen: Timer
en Logger
Stap-voor-stap hulp:
check_solution
, display_info
).name
, time_remaining
).str
, int
, bool
, None
, List[str]
, enzovoort.README.md
in jouw modulemap met: