Sto facendo un diagramma di classe per un progetto di gioco, ma sono bloccato su un problema di accoppiamento.
Contesto
Il projet è un gioco a turni. Stanno giocando due utenti Hanno unità su una mappa. Giocano fino a quando 1 giocatore non ha tutte le sue unità morte o se viene raggiunto un numero predefinito di turni. Ad ogni round, ogni giocatore rivedrà le sue unità una ad una:
- può spostare un'unità fino a quando l'unità non ha alcun punto movimento rimasto
- può saltare il turno dell'unità
Modeling
Classiirrilevantialledomandesonostatetagliate
Laclassedigiococontienetuttiglioggettipertinenti:igiocatori,leunità,ilturnocorrente(qualegiocatore(i)hannogiàgiocato,chièilprossimo,...).L'oggettoTurnocontieneunoggettoPlayerTurn,chetienetracciadiqualiunitàsonogiàstategiocate,qualiunitàvengonolasciateagiocare,...
Problema
->SupponiamodicreareilmetodoGetNextPlayableUnit(nellaclassePlayerTurn).
Dovremoiterareattraversoleunitàdelgiocatorecorrenteetrovarneunachenonsianellalista"PlayedUnits". Pertanto, dovremo chiamare Game.Units.GetUnits con il parametro Game.Turn.CurrentPlayer ( Game si riferisce all'istanza del gioco corrente).
- > Supponiamo di creare il metodo MoveTo (nell'unità di classe).
Se l'Unità non ha alcun punto movimento rimasto, dovremo chiamare Game.Turn.PlayerTurn.Finish che selezionerà la successiva unità giocabile o finirà il turno del giocatore corrente se ha già giocato tutte le sue unità in questo turno.
- > ... Ci sono molti altri scenari in cui avremo bisogno di accedere al metodo di altre classi. Ad esempio, un metodo di "Kill" sull'Unità dovrà controllare se il giocatore corrente ha ancora almeno 1 unità in vita, e dovrà chiamare un metodo Finish su Gioco altrimenti.
Domanda
Penso che l'accoppiamento non possa essere evitato (correggimi se sbaglio comunque!). Ho pensato a due possibili modi di affrontare l'accoppiamento:
Soluzione 1
Durante la costruzione di istanze di queste classi, potrei passare l'istanza del gioco corrente. Dopotutto, ha senso: istanze Unit, istanze Turn, ... appartengono tutte a un gioco. Quindi, potrei implementare i metodi GetNextPlayableUnit, MoveTo, Killed, ... facilmente usando questa istanza. In qualche modo, non mi sento a mio agio a condividere l'istanza del gioco corrente tra tutte le classi del modello, anche se ho letto qua e là che era il principio dell'iniezione di dipendenza.
Soluzione 2
- Analizza le dipendenze del metodo: ad esempio, il metodo Kill dipende da Game.Units.Unit.Player (per recuperare il giocatore che possiede l'unità), su Game.Units.GetUnits (per trovare tutte le altre unità possedute dal giocatore), su Game.End per terminare il gioco se il numero di unità del giocatore ha raggiunto 0.
- Trova le dipendenze root comune : nell'esempio sopra, la radice comune tra Game.Units.Unit, Game.Units e Game is Game. In un altro esempio, se avessimo le dipendenze Game.Units.Unit & Game.Units.SomethingElse, la radice comune sarebbe Game.Units.
- Implementa il metodo in questa classe root comune . Ci è garantito che non è necessario accedere alle classi genitore (nella gerarchia dell'associazione).
I rischi:
- molti metodi avranno la classe Game per root comune = > molti metodi in Game class = > un sacco di codice nella classe Game. I metodi
- non appartengono alle loro giuste classi. Considera il metodo "KillUnit": ti aspetteresti di trovarlo direttamente nella classe Unità, non nella classe Game. Lo stesso vale per "MoveTo", "Finish", ...
C'è qualche altra soluzione a cui puoi pensare? Quale sarebbe l'approccio migliore in questo caso particolare?