Question

J'entends souvent ici des gens de développement conduit de test ayant une fonction obtenir de grandes quantités d'information est implicitement une mauvaise chose. Je vois que ce serait Étiez mauvais du point de vue de l'essai, mais est-il pas parfois nécessaire du point de vue d'encapsulation? La question suivante vient à l'esprit:

utilise-t-aléatoire et OrderBy un bon algorithme de lecture aléatoire

En fait, quelqu'un a voulu créer une fonction en C # pour mélanger un tableau au hasard. Plusieurs personnes lui ont dit que le générateur de nombres aléatoires doit être transmis en tant que paramètre. Cela semble être une violation flagrante de l'encapsulation pour moi, même si elle ne fait tester plus facilement. N'est pas le fait qu'un algorithme nécessite une gamme brassage tout état autre que le tableau, il est un détail de brassage mise en œuvre que l'appelant ne devrait pas avoir à se soucier? Ne serait-pas le bon endroit pour obtenir ces informations implicitement, peut-être d'un singleton thread local?

Était-ce utile?

La solution

Oui, qui ne casse encapsulation . Comme avec la plupart des décisions de conception de logiciels, c'est un compromis entre deux forces opposées. Si vous le RNG encapsulez alors vous rendre difficile de changer pour un test unitaire. Si vous faites un paramètre alors vous rendre facile pour un utilisateur de changer le RNG (et potentiellement se tromper).

Ma préférence personnelle est de le rendre facile à tester, puis fournir une implémentation par défaut (un constructeur par défaut qui crée son propre RNG, dans ce cas particulier) et une bonne documentation pour l'utilisateur final. L'ajout d'une méthode avec la signature

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

qui crée un Random en utilisant le temps de système actuel comme semence prendrait soin de la plupart des cas d'utilisation normale de cette méthode. La méthode originale

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

peut être utilisé pour le test (passage dans un objet Random avec une graine connue) et aussi dans les rares cas où un utilisateur décide qu'ils ont besoin d'un RNG cryptographiquement sécurisé. La mise en œuvre d'un paramètre doit appeler cette méthode.

Autres conseils

Je ne pense pas qu'il casse l'encapsulation. Le seul état du tableau est les données lui-même - et « une source de hasard » est essentiellement un service. Pourquoi un tableau doit avoir naturellement une source associée de hasard? Pourquoi qui doivent être un singleton? Qu'en est-il des situations qui ont des exigences différentes - par exemple vitesse vs aléatoire cryptographiquement sécurisé? Il y a une raison pour laquelle java.util.Random a une sous-classe de SecureRandom :) Peut-être qu'il n'a pas d'importance si les résultats de lecture aléatoire sont prévisibles avec beaucoup d'efforts et d'observation - ou peut-être fait. Cela dépendra du contexte, et que l'information est que l'algorithme de lecture aléatoire ne doit pas se soucier.

Une fois que vous commencez à penser comme un service, il est logique qu'il est passé comme dépendance.

Oui, peut l'obtenir à partir d'un singleton fil local (et en fait, je vais blog sur exactement que dans les prochains jours) mais je généralement du code pour que le < em> appelant arrive à prendre cette décision.

L'un des avantages du « hasard en tant que service » concept est qu'il fait pour la répétabilité - si vous avez un test qui échoue, vous pouvez passer dans un Random avec une graine spécifique et savez que vous aurez toujours le même les résultats, ce qui rend le débogage.

Bien sûr, il y a toujours la possibilité de faire la Random en option -. Utiliser un singleton thread local par défaut si l'appelant ne fournit pas leur propre

Je ne pense pas que cela viole l'encapsulation.

Votre exemple

Je dirais qu'être en mesure de fournir un RNG est une caractéristique de la classe. Je fournirais évidemment une méthode qui ne nécessite pas, mais je peux voir moments où il peut être utile de pouvoir dupliquer la randomisation.

Que faire si le shuffler tableau faisait partie d'un jeu qui a utilisé le RNG pour la production de niveau. Si un utilisateur a voulu enregistrer le niveau et jouer plus tard, il peut être plus efficace pour stocker les graines de RNG.

Cas général

classes simples qui ont une seule tâche comme celui-ci, généralement, ne pas besoin de se soucier de divulguer leur fonctionnement interne. Ce qu'ils encapsulent est la logique de la tâche, et non pas les éléments requis par cette logique.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top