Domanda

Sento spesso da queste parti da una prova su strada di persone di sviluppo che hanno una funzione di ottenere grandi quantità di informazioni è implicitamente una brutta cosa. Posso vedere erano questo sarebbe un male dal punto di vista di prova, ma non è a volte necessario dal punto di vista incapsulamento? La seguente domanda viene in mente:

sta usando a caso e OrderBy un buon algoritmo di riordino ?

In sostanza, qualcuno ha voluto creare una funzione in C # per mescolare in modo casuale un array. Diverse persone gli hanno detto che il generatore casuale di numeri dovrebbe essere passato come parametro. Questa sembra una palese violazione di incapsulamento per me, anche se non rende il test più facile. Non è il fatto che una serie mischiare algoritmo richiede qualsiasi stato del tutto diverso da quello della matrice è mischiare un dettaglio di implementazione che il chiamante non avrebbe dovuto preoccuparsi? Non sarebbe il luogo corretto per ottenere queste informazioni implicitamente, forse da un Singleton thread-locale?

È stato utile?

Soluzione

Sì, che si rompe incapsulamento . Come con la maggior parte delle decisioni di progettazione software, questo è un compromesso tra due forze opposte. Se si incapsulare il RNG, allora si rendono difficile cambiare per una prova di unità. Se si fanno un parametro, allora si rendono facile per un utente di modificare il RNG (e potenzialmente sbaglia).

La mia preferenza personale è quello di rendere più facile per testare, quindi fornire un'implementazione di default (un costruttore di default che crea il proprio RNG, in questo caso particolare) e una buona documentazione per l'utente finale. L'aggiunta di un metodo con la firma

public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source)

che crea un Random utilizzando l'ora di sistema corrente come il suo seme sarebbe preso cura della maggior parte dei normali casi di utilizzo di questo metodo. Il metodo originale

public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)

potrebbe essere utilizzato per il test (passare un oggetto Random con un seme noto) e anche in quei rari casi in cui un utente decide hanno bisogno di un RNG crittograficamente sicuro. L'implementazione di un parametro deve chiamare questo metodo.

Altri suggerimenti

Non credo che si rompe l'incapsulamento. L'unico stato nella matrice è i dati stessi - e "una fonte di casualità" è essenzialmente un servizio. Perché una serie dovrebbe avere naturalmente una fonte associato di casualità? Perché dovrebbe esserci un Singleton? Che dire di diverse situazioni che hanno esigenze diverse - per esempio Velocità vs casualità crittograficamente sicuro? C'è un motivo per cui java.util.Random ha una sottoclasse SecureRandom :) Forse non importa se i risultati del riordino sono prevedibili con un sacco di fatica e di osservazione - o forse lo fa. Questo dipenderà dal contesto, e questo è le informazioni che l'algoritmo shuffle non dovrebbe preoccuparsi.

Una volta che si cominci a pensare ad esso come un servizio, ha senso che è passato come una dipendenza.

Sì, è potrebbe ottenere da un Singleton thread-local (e infatti ho intenzione di blog su esattamente che nei prossimi giorni), ma vorrei in genere il codice in modo che il < em> chiamante arriva a prendere questa decisione.

Uno dei vantaggi della "casualità come un servizio" concetto è che rende per la ripetibilità - se hai un test che riesce, è possibile passare in un Random con un seme specifico e sai che dovrai sempre ottenere lo stesso risultati, che fa più facile il debug.

Naturalmente, c'è sempre la possibilità di fare il Random opzionale -. Utilizzare un Singleton thread-local come default se il chiamante non fornisce il proprio

Non credo che questo viola l'incapsulamento.

Il tuo Esempio

Direi che essere in grado di fornire un RNG è una caratteristica della classe. Vorrei ovviamente fornire un metodo che non richiede, ma posso vedere volte in cui può essere utile per essere in grado di duplicare la randomizzazione.

Che cosa succede se lo shuffler serie era parte di un gioco che ha utilizzato il RNG per la generazione di livello. Se un utente voleva salvare il livello e giocare di nuovo in seguito, può essere più efficace per conservare il seme RNG.

Caso generale

classi semplici che hanno un unico compito come questo in genere non hanno bisogno di preoccuparsi di divulgare il loro funzionamento interno. Quello che incapsulano è la logica del compito, non gli elementi richiesti da questa logica.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top