"Tell, do not ask" lavora sulla premessa che un oggetto non dovrebbe essere obbligato a fare qualcosa in base ad alcune informazioni sull'oggetto stesso. Sicuramente l'oggetto dovrebbe conoscere il proprio stato? Non dovresti dover accoppiare codice al di fuori dell'oggetto per svolgere qualche funzione che potrebbe benissimo fare da solo. Ho trovato la foto di esempio terribilmente confusa, quindi userò un altro esempio.
Immagina di giocare a un gioco complesso come World of Warcraft. Sei un warlock e vuoi usare l'incantesimo Fear su qualche altro giocatore. L'incantesimo dovrebbe mandarli in esecuzione per 8 secondi. Se lo lanci di nuovo, quel tempo sarà dimezzato a causa di rendimenti decrescenti e così via. Ci sono molti fattori che decidono se l'incantesimo dovrebbe essere un successo o meno.
Ora, l'incantesimo Fear potrebbe essere implementato in questo modo:
function castFear(Player player) {
if (player->isAPaladinAndFearsNothing())
return false;
if (player->hasTakenAntiFearPotion())
return false;
if (currentPlayer->getStat("shadow_magic_power") < player->getStat("shadow_magic_resistance"))
return false;
player->receiveFear();
}
Con "tell, do not ask" questo codice potrebbe essere semplificato drasticamente:
function castFear(Player player) {
player->receiveFear(currentPlayer);
}
La classe Player potrebbe essere implementata in questo modo:
class Player {
public boolean receiveFear(Player castingPlayer) {
if (this->isAPaladinAndFearsNothing())
return false;
if (this->hasTakenAntiFearPotion())
return false;
if (castingPlayer->getStat("shadow_magic_power") < this->getStat("shadow_magic_resistance"))
return false;
// Get feared
}
}
Ora, entrambe le soluzioni potrebbero sembrare abbastanza simili, ma se ci pensate, di chi è la responsabilità di sapere se il giocatore bersaglio può essere temuto o no? "Tell, do not ask" potrebbe apparire come un "trucco pulito", ma ho trovato questo stile di codifica come uno dei capisaldi di OOP. Non si dovrebbe sapere di quale complessità sia nascosta dietro quella funzione pubblica e come tale non dovrebbe nemmeno agire contro di essa. E se alcuni dei tuoi nuovi incantesimi dovessero anche temere il tuo obiettivo? Dovresti rimanere aggiornato su tutti i controlli che dovresti fare, ovunque. Se volevi implementare "Healing Horror" che teme il tuo obiettivo e ti guarisce, potresti semplicemente scrivere:
function castHealingHorror(Player player) {
currentPlayer->health += 50;
player->receiveFear(currentPlayer);
}
Direi che questa è anche una domanda su quale oggetto dovrebbe eseguire i controlli, il mittente o il destinatario? Ci pensiamo. Se dovessi inviare una lettera a un funzionario contenente una formulazione inappropriata, la tua lettera non verrebbe interrotta da qualche parte lungo la strada? Per quanto ne sai qualcuno potrebbe leggere la posta prima che il tuo destinatario lo faccia e filtrarlo come misura di sicurezza. Dovresti codice per questo come il mittente? Tutto quello che devi fare è prendere l'oggetto Letter
preparato, darlo al postino e basta. Forse non raggiunge nemmeno l'ufficio postale di destinazione a causa di qualche inconveniente.
Esponiti alla minore complessità e informazione possibile e lascia che ogni componente gestisca le proprie regole aziendali. È quindi più facile combinarli in un sistema completamente incapsulato.