Il parametro method accetta oggetti dalla propria classe?

2

Non sono assolutamente sicuro se questo è il posto giusto per questa domanda. Ma credo che StackOverflow non sarà il posto giusto.

È per un motivo qualsiasi un cattivo modo per passare un oggetto ad un metodo dalla stessa classe? Per qualche motivo non mi sento bene con la prima soluzione.

Il metodo Start inizia il gioco con il giocatore dato.

CurrentGame.Start(CurrentGame.CurrentPlayer);

o

CurrentGame.StartWithCurrentPlayer();

Ma l'ultimo metodo potrebbe richiedere un secondo metodo come:

public void SetCurrentPlayer(Player player)
{
    CurrentPlayer = player;
}
    
posta Lucas 04.10.2013 - 22:08
fonte

5 risposte

3

Una riga come CurrentGame.CurrentPlayer sarebbe un odore di codice per me. In effetti c'è qualcosa di sospetto nell'intera domanda.

Dici che il secondo metodo, StartWithCurrentPlayer , richiederebbe un ulteriore metodo SetCurrentPlayer . Ma come è diverso da ciò che CurrentGame.CurrentPlayer è già nel primo metodo? Da dove viene il valore per CurrentPlayer ?

Qui sembrano esserci 3 possibili scenari, nessuno dei quali ha davvero senso con nessuno dei tuoi approcci:

  1. Il gioco non conosce nulla dei giocatori finché non viene avviato.

    In questo scenario, mi aspetto di vedere un metodo come questo all'interno della classe Game :

     public void Start(Player player)
     {
         // Set stuff up
         this.currentPlayer = player;
     }
    
  2. Il giocatore può essere modificato in qualsiasi momento.

    Questo è un caso d'uso legittimo, ad es. giochi arcade o multiplayer. Però è un po 'difficile da pianificare. Avresti una classe simile a questa:

     public void Start()
     {
         LoadLevel(CurrentPlayer.LastLevel);
         // Or whatever - some stuff that depends on CurrentPlayer
     }
    
     public Player CurrentPlayer
     {
         get { ... }
         set { ... }
     }
    

    Dovresti fare molta attenzione per assicurarti di eseguire il setup / cleanup corretto quando CurrentPlayer è cambiato, altrimenti prevedo strani errori dovuti a Accoppiamento sequenziale . Ad esempio, cosa succede quando provi ad avviare una partita senza impostare qualsiasi giocatore? Tuttavia, questa è una decisione di progettazione, non necessariamente un errore.

  3. Il giocatore deve essere configurato prima di iniziare una partita.

    Questo significa essenzialmente che Game non ha vita o significato propri senza un oggetto Player , che grida per un albero delle dipendenze:

     public class Game
     {
         private readonly Player player;
    
         public Game(Player player)
         {
           if (player == null) throw new ArgumentNullException("player");
           this.player = player;
         }
    
         public void Start() { ... }
     }
    

Il tuo primo esempio viola il principio Tell, Do not Ask . Non dovresti mai (beh, raramente) aver bisogno di chiamare un metodo su un oggetto e fornire i stesso oggetto dati come parametro. Questo è esattamente il tipo di ciò che OOP è progettato per evitare con l'incapsulamento.

Il secondo esempio originale è simile al # 2. È potenzialmente corretto, ma solo se questo è effettivamente il tuo intento, ed è anche il più complicato.

Prova a pensare alle vite degli oggetti. # 1 implica che il Game duri per sempre, ma se cambi Player devi riavviare il gioco. # 2 implica che il Game duri per sempre, ma continua dal punto corrente anche quando viene modificato Player . E # 3 implica che il Player possa durare molto più del Game (per esempio un gioco di ruolo). Tutti sono validi, ma usa quello appropriato per la tua situazione particolare.

    
risposta data 05.10.2013 - 15:10
fonte
3

La prima via sembra la migliore ( CurrentGame.Start(CurrentGame.CurrentPlayer); ). Puoi quindi nutrirlo con qualsiasi giocatore desideri. succede solo per caso che il tuo esempio usa un giocatore stabilito dal tuo attuale scope.

    
risposta data 04.10.2013 - 23:39
fonte
2

Questo dipende, in parte, da quale pezzo di codice è responsabile per controllare chi è il giocatore corrente. È CurrentGame o il codice che usa CurrentGame ("il chiamante")?

Se CurrentGame è responsabile per l'impostazione del prossimo giocatore dopo che il turno di CurrentPlayer è finito, allora l'esposizione di SetCurrentPlayer darebbe al chiamante un modo per interferire con lo stato di CurrentGame . Ad esempio, se il giocatore A termina il proprio turno, CurrentGame imposterà CurrentPlayer su Giocatore B; tuttavia, il chiamante potrebbe utilizzare questo metodo per impostare CurrentPlayer sul giocatore A prima che il turno del giocatore B sia terminato.

Se il chiamante è responsabile:

La tua prima opzione sarebbe praticabile, sebbene il chiamante potrebbe essere eccessivamente dipendente dall'utilizzo di una proprietà di CurrentGame per ricordare chi stava giocando l'ultima partita.

Se CurrentGame è responsabile:

Considera un approccio diverso, ad esempio:

CurrentGame.SetPlayers(OrderedList<Player>)

Il chiamante passerebbe nell'elenco dei giocatori che è ordinato in base alla sequenza dei loro turni. CurrentGame avrebbe quindi impostato CurrentPlayer sul primo giocatore nell'elenco quando il gioco inizia.

    
risposta data 05.10.2013 - 03:58
fonte
0

Personalmente sceglierei la prima opzione, perché trovo che metodi come la seconda opzione siano troppo specifici. Tuttavia, se avessi una serie di giocatori nella tua classe, potresti invece passare l'indice dell'array.

All'interno di CurrentGame avresti qualcosa di simile al seguente per una partita a quattro giocatori:

Player[] players = new Player[4];

Quindi per avviare i giocatori:

CurrentGame.Start(0);
CurrentGame.Start(1);
CurrentGame.Start(2);
CurrentGame.Start(3);
    
risposta data 04.10.2013 - 23:44
fonte
0

La prima opzione è migliore dato che @brad ha già risposto, ma vorrei suggerire di non accedere esplicitamente a CurrentPlayer , ma invece usare un getter getCurrentPlayer() . IMHO dovresti avere un setter troppo setCurrentPlayer . Forse oggi non hai molti calcoli da fare e setCurrentPlayer è solo un compito come esempio, ma se usi già setter / getter hai incapsulato tutta la logica relativa a setCurrentPlayer all'interno di un metodo.

Getters & I setter sono un modello di design ben noto. Puoi trovarne di più qui ( link ) per esempio.

    
risposta data 05.10.2013 - 03:40
fonte

Leggi altre domande sui tag