Modifica temporaneamente lo stato dell'oggetto per salvare il passaggio dei parametri

0

Dire, ho un agente il cui stato include position e facing_direction . Devo controllare se può muoversi in qualsiasi direzione o è completamente bloccato (a causa di vari ostacoli). Gli agenti hanno un metodo can_move() che controlla se l'agente può spostarsi in avanti, cioè lungo il suo facing_direction .

Posso modificare facing_direction dell'agente per esaminare tutte le direzioni possibili in un ciclo, quindi chiamare can_move() . Alla fine, restituire facing_direction dell'agente al suo valore originale. Tuttavia, questo sembra un po 'imbarazzante, dal momento che sto cambiando lo stato solo per eseguire un calcolo, non per girare o spostare effettivamente l'agente. Questo approccio è considerato una tecnica accettabile? Ha degli svantaggi (in un programma a thread singolo)?

L'alternativa, naturalmente, è il metodo refactor can_move() per accettare la direzione come parametro. Ciò comporterebbe la copia di quel parametro tra diversi metodi coinvolti nel calcolo e il rischio di confusione tra questo parametro e la direzione effettiva del fronte memorizzata nell'istanza dell'agente.

Sto usando python ma dubito che questa domanda avrebbe risposte diverse in lingue diverse purché non sia un linguaggio puramente funzionale.

    
posta max 25.01.2017 - 01:01
fonte

1 risposta

3

La tua soluzione attuale suona come un hack, per due motivi:

  • Stai chiedendo all'agente per alcune informazioni, ma per farlo devi anche emettere comandi come "gira a sinistra". In genere è meglio praticare la separazione tra richieste e query poiché ciò rende più chiaro quando una chiamata al metodo cambia lo stato dell'oggetto.

    Di per sé, cambiare lo stato dell'agente per sondare in direzioni diverse non è problematico in quanto l'agente si troverà nella stessa direzione prima e dopo la chiamata al metodo. Tuttavia, la modifica dello stato dell'oggetto introduce in modo intermittente fragilità: cosa accade quando un'eccezione viene lanciata prima che l'agente sia tornato al loro orientamento originale? Tieni anche la post-condizione "l'agente affronta nella direzione originale"? Cosa succede se il numero di turni è associato ad un certo costo o è tracciato? Per esempio. se questo è un gioco di puzzle, il punteggio del gioco potrebbe prendere in considerazione il numero di turni. L'implementazione del controllo bloccato in termini di rotazione dell'agente potrebbe influenzare direttamente il punteggio del gioco.

    Si noti che in Python, l'impostazione di un campo di istanza può avere effetti collaterali sconosciuti se tale campo di istanza è implementato come proprietà. Al contrario, l'impostazione di un campo membro è sempre "sicura" in un linguaggio come Java.

  • Le operazioni fornite dall'agente e le operazioni richieste nel programma non corrispondono. Vuoi sapere se un agente è bloccato, quindi dovrebbe avere un metodo agent.is_stuck() -> bool . Poiché tale metodo è interno all'agente, può utilizzare direttamente la stessa logica di agent.can_move_in_facing_direction() senza la necessità di modificare lo stato dell'oggetto. Probabilmente estrai la logica comune in un metodo di supporto come self.__can_move_in_direction(d) .

Come problema di progettazione generale, non è una buona idea usare qualsiasi cosa tranne i parametri di funzione per passare i parametri di funzione. L'utilizzo dei campi di istanza non è fondamentalmente diverso dall'uso di variabili globali per comunicare i parametri. È l'equivalente morale di:

# params for add
x = None
y = None
result = None

def add():
  result = x + y

# invoke add
x = 40
y = 2
add()
print(result)  #=> 42

Questo ha i suoi usi? Sì, nella programmazione di assembly con spazio limitato in cui è necessario impedire le allocazioni dello stack. Ma nelle lingue di alto livello? Non proprio.

Il problema con le variabili globali (o, in realtà, qualsiasi variabile con un ambito di grandi dimensioni) è che è sempre più difficile tenere traccia di come viene utilizzata tale variabile. Se uso una variabile ish globale e chiamo una funzione, ho bisogno di sapere se la funzione chiamata modifica direttamente o indirettamente quella variabile. Tenere traccia del comportamento esatto di tutte quelle funzioni va da difficile (se ci sono molte funzioni che potrebbero influenzare quelle variabili) a impossibile (se infinite funzioni potrebbero essere aggiunte ereditando la tua classe). È difficile capire il comportamento di queste funzioni poiché non dipendono solo dai loro parametri espliciti, ma implicitamente anche dallo stato del mondo che li circonda.

Lo stato di muting è il meno possibile e mantenere uno stato mutabile incapsulato e diviso in piccoli pezzi coesivi non è solo una questione di "codice pulito", è fondamentale per mantenere comprensibile un grande code base.

    
risposta data 25.01.2017 - 11:00
fonte

Leggi altre domande sui tag