Il concetto
Sto programmando un'interfaccia su pygame come un progetto personale, per semplificare la creazione di giochi.
Finora sono riuscito a progettare un'architettura che si comporta in questo modo:
- Gli oggetti sono componenti visualizzabili che possono apparire e spostarsi sullo schermo
- Gli oggetti possono avere oggetti figli
- Quando un oggetto viene visualizzato, chiede a tutti i suoi figli di visualizzarsi sulla superficie del genitore.
- Gli oggetti hanno tre elementi importanti: un sistema di callback, un sistema grafico e un sistema fisico per agire, visualizzare e spostare rispettivamente.
Quindi, quando voglio creare una "scena" di gioco, creo un oggetto "radice" che contiene altri oggetti come il giocatore, il mouse, il terreno, i mostri ...
Quindi devo solo chiedere alla root di visualizzarsi, e ogni oggetto appare in modo ricorsivo.
L'ho progettato senza conoscere il modello composito all'inizio, solo le basi di OOP.
Il mio problema principale era rendere la proprietà di sostituibilità degli oggetti che proviene dall'ereditarietà per funzionare bene con la composizione ricorsiva che ho creato.
Voglio dire che ho una classe "astratta" chiamata "Object" (ho messo l'abstract tra virgolette perché Python non ha davvero un tale concetto) che è ereditato da classi come "Image" (per essere in grado di visualizzare) o "MovingObject" (per essere in grado di spostarsi). Qui, l'ereditarietà ha lo scopo di estendere le mie abilità oggettuali.
Ma il mio pattern composito richiede che "i gruppi di oggetti debbano essere considerati uguali ai singoli oggetti".
Quindi quando chiamo ricorsivamente un metodo da un oggetto, chiama quel metodo da ogni figlio dell'oggetto, indipendentemente dal fatto che alcuni di essi potrebbero non avere quel metodo.
Esempio
Ad esempio, utilizziamo questo elemento root:
- root (Immagine)
- player (MovingObject)
- cloud (MovingObject)
- background (immagine)
- sole (immagine)
Ora supponiamo di voler chiamare il metodo move()
sull'elemento root, per far muovere ogni bambino: in primo luogo, non possiamo perché root è un'istanza Image, quindi non conosce il metodo move()
. Ma anche se fosse il caso, i bambini "sfondo" e "sole" non lo saprebbero.
Quindi ho deciso di mettere un metodo vuoto move()
nella mia classe Object "astratta", quindi ogni oggetto lo sa, anche se non fa nulla.
Il problema è che la mia classe Object ora contiene metodi vuoti che non capisce e non ha bisogno, solo per consentire il comportamento ricorsivo.
Possibile soluzione
Poi ho sentito di tutto il trambusto dell'ereditarietà e della composizione e una delle soluzioni che mi è venuta in mente è stata quella di smettere di usare l'ereditarietà per le abilità Oggetto e usare invece la composizione. Ciò significa che vorrei creare, ad esempio, una classe "Body", una classe "Image" e una classe "Callback" che rappresentino azioni diverse, e quindi inserirle in un'istanza Object per "dotarla" e dargli più potenza .
Ma poi ho pensato che questo cambierebbe appena qualcosa, perché dovrò chiamare move()
, e poi l'oggetto controllerà se ha il plug-in Body e lo userà. Ma richiede ancora il metodo move()
per essere presente nella classe Object.
Domande
Quindi mi rivolgo a voi ragazzi per darmi consigli sul mio schema:
- Ho capito bene come funziona il pattern composito?
- Il mio approccio è corretto?
- L'uso delle classi "plug-in" mi aiuterà?
- Il comportamento ricorsivo è una buona idea?
- Esistono altri modelli più adatti alle mie esigenze?
Spero che tu possa darmi qualche suggerimento!