La mia struttura di classe è abbastanza buona?

3

Quindi volevo provare questa sfida su reddit che riguarda principalmente il modo in cui struttura i tuoi dati il meglio che puoi. Ho deciso di sfidare le mie abilità in C ++. Ecco come l'ho pianificato.

  • Innanzitutto, c'è la classe Gioco . Si occupa del tempo ed è l'unica a cui la principale ha accesso.
  • Un gioco ha una foresta . Per ora, questa classe non ha molte cose, solo una taglia e una fabbrica . Verrà usato meglio quando arriverà in SDL-roba immagino
  • Una Fabbrica è la cosa che si occupa degli Oggetti del Gioco (a.k.a. Alberi, Lumberjack e Orsi). Ha un vettore di tutti GameObjects e una coda di eventi che saranno gestiti alla fine di un mese.
  • A GameObject è una classe astratta che può essere aggiornata e che può notificare il Listener di eventi
  • Il EventListener è una classe che gestisce tutti gli eventi di una simulazione. Può ricevere eventi da un oggetto di gioco e avvisare Factory se necessario, quest'ultimo gestirà correttamente l'evento.

Pertanto, le classi Albero , Taglialegna e Orso ereditano tutte da GameObject . E Alberello e Elder Tree ereditano da Albero .

Infine, un Evento è definito da un enumerazione event_type (LUMBERJACK_MAWED, SAPPLING_EVOLUTION, ...) e da un event_protagonists union (un GameObject o un paio di GameObject (chi ha ucciso chi?)).

All'inizio ero piuttosto contento di questo perché sembra abbastanza logico e flessibile. Ma alla fine ho messo in discussione questa struttura. Ecco perché:

  1. Non mi piace il fatto che un GameObject debba conoscere la Factory. In effetti, quando un orso si muove da qualche parte, deve sapere se c'è un boscaiolo! Oppure è la fabbrica che gestisce luoghi e oggetti. Sarebbe bello se un GameObject potesse interagire solo con EventListener ... o forse non è un grosso problema.
  2. Non sarebbe meglio se separassi la fabbrica in tre vettori? Uno per ogni tipo di GameObject. L'idea sarebbe di ottimizzare la ricerca. Se sto cercando di eliminare un taglialegna morto, dovrei solo guardare in un vettore più breve piuttosto che in un vettore molto lungo.
  3. Un altro problema sorge quando voglio sapere se c'è un particolare oggetto in un determinato caso perché devo cercare tutti gli oggetti di gioco e vedere se sono nel caso specifico. Tenderei a pensare che l'altra idea sarebbe usare una matrice, ma il problema sarebbe che avrei casi vuoti (e quindi spazio inutilizzato).
  4. Non so davvero se Alberello e Elder Tree dovrebbero ereditare da Albero . In effetti, un alberello è un albero, ma per quanto riguarda la sua evoluzione? Dovrei semplicemente cancellare l'alberello e dire alla fabbrica di creare un nuovo albero nello stesso identico posto? Non mi sembra naturale farlo. Come potrei migliorare questo?
  5. Il design di un evento è abbastanza buono? Non ho mai usato unions prima in C ++ ma non avevo altre idee su cosa usare.

Bene, spero di essere stato abbastanza chiaro. Grazie per aver dedicato del tempo per aiutarmi!

    
posta Rivten 24.08.2014 - 01:25
fonte

1 risposta

2
  1. Se comprendo il tuo progetto, non è necessario che GameObject conosca il tipo Factory . L'unico caso in cui un GameObject dovrebbe accedere a una factory è quando è necessario creare un altro GameObject , che è comune per gli oggetti che generano altri oggetti. Tuttavia, dal momento che stai già utilizzando un sistema di eventi, puoi semplicemente definire un tipo di evento come "crea oggetto". In questo modo, il tipo GameObject può generare / creare altri oggetti attivando un evento, senza conoscere l'esistenza di un Factory .

  2. No, non è una buona idea separare GameObjects da "type", GameObject dovrebbe essere un'astrazione, se inizi a digitarlo, perdi quell'astrazione e crei l'accoppiamento. Inoltre, questo non sarebbe scalabile se tu dovessi introdurre un altro special specializzato GameObject "type". Richiederebbe di cambiare la fabbrica per aggiungere un altro contenitore per questo nuovo tipo. OOP-saggio, è meglio mantenere il GameObject astratto.

  3. Puoi ottimizzare la ricerca e la gestione di GameObjects utilizzando una struttura dati più efficiente. Un grafico delle scene o un quadrifoglio può ridurre il numero di query quando si ha a che fare con un sacco di GameObjects di spread in un dato spazio. Inoltre, per il caso specifico di rimozione, è possibile delegare tale attività a GameObject stessa. Quando l'oggetto è scaduto, falla generare un evento: es .: new Event_RemoveObject(this) che si passa come argomento dell'evento. Quando l'evento viene gestito, il gestore eventi saprà chi eliminare.

  4. Se vuoi progettare per la scalabilità, è meglio evitare l'ereditarietà. Prendendo il caso Tree , altri tipi più specifici di alberi non hanno bisogno di essere oggetti a sé stanti. È possibile utilizzare i parametri di configurazione per definirlo. Questo è altrimenti noto come Component Based Design . Definisci il comportamento di GameObject dal set dei suoi componenti. Questo rende un approccio molto flessibile ed estensibile.

  5. Sì, puoi usare un C ++ union per definire un tipo Variant .

Questo è un esempio che ho usato prima:

union Data {
    void *    asVoidPtr;
    bool      asBoolean;
    int       asInteger;
    float     asFloat;
    char *    asCString;
    Vector3 * asVector3;
    Vector4 * asVector4;
};
// Plus an enum flag that tell which field of the
// union is in use, e.g.: a "type tag"

Dovrebbe essere sufficiente se i parametri dei tuoi eventi sono solo tipi primitivi e puntatori grezzi. Se hai bisogno di parametri più complessi come oggetti e puntatori intelligenti, la soluzione migliore è definire una classe Event astratta e specializzarla, se necessario.

    
risposta data 24.08.2014 - 04:03
fonte

Leggi altre domande sui tag