Come gestire l'accoppiamento nelle classi del modello

2

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

  1. 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.
  2. 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.
  3. 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?

    
posta Maxime 08.11.2014 - 22:37
fonte

1 risposta

2

Chiedete altre soluzioni. Queste potrebbero essere riflessioni sul tuo processo di ricerca di soluzioni:

  1. Questa è la tua prima versione del diagramma e non vuoi buttarla via e ricominciare. È più probabile che mescoli pensieri vecchi, forse irrilevanti con pensieri nuovi.
  2. Mentre modellisti pensi di implementarlo. Questo mescola il modo in cui pensi che dovrebbe essere il modello e come il linguaggio di programmazione vuole che assomigli. La modellazione non sta implementando. Dovresti finire con più metodi e, si spera, più classi nella tua implementazione rispetto al tuo modello.
  3. Penso che la classe Unità sia un modo per attuare il comportamento desiderato. Può essere rilasciato al tuo livello di granularità. Ad esempio, la classe Player non punta a una sottoclasse String PlayerName. Mantieni un livello di granularità nei tuoi diagrammi.
  4. Iniziare con un diagramma di classe potrebbe non essere la scelta. Un diagramma di oggetti è più specifico. I diagrammi delle classi sono più generali. Quindi penso che ci si possa perdere nelle generalizzazioni che non hanno bisogno di senso.
  5. Hai diversi scenari, giochi. Puoi creare diversi diagrammi di oggetti da loro e generalizzare da lì. Non c'è bisogno di mettere tutto in un diagramma in una volta.

Per la tua preoccupazione: il comportamento può essere trovato in diversi metodi Unit.Die() Playfield.RemoveUnit() , Player.KillUnit() allo stesso tempo. Va bene. Ma vuoi evitare di copiare e incollare il codice in ogni metodo.

Informazioni sull'accoppiamento. Penso che tu / puoi / devi / non vuoi evitare l'accoppiamento. Alcuni oggetti dovrebbero interagire. Un caso negativo è quando tutti gli oggetti interagiscono sempre con tutti gli altri oggetti in ogni metodo. Si tratta di un accoppiamento troppo lungo senza separazione delle preoccupazioni .

E forse un parere obsoleto: OOP riguarda gli oggetti e le loro interazioni, non le classi, non l'ereditarietà.

    
risposta data 09.11.2014 - 14:09
fonte