Pregunta

A menudo escucho por aquí de prueba de conducción del desarrollo de las personas que tienen una función de obtener grandes cantidades de información de forma implícita es una mala cosa. Puedo ver eran esto sería malo desde el punto de vista de pruebas, pero a veces no es necesario desde el punto de vista de encapsulación? La siguiente pregunta viene a la mente:

está utilizando aleatoria y OrdenarPor un buen algoritmo aleatorio ?

Básicamente, alguien quería crear una función en C # para barajar al azar una matriz. Varias personas le dijeron que el generador de números aleatorios se debe pasar como parámetro. Esto parece como una violación flagrante de encapsulación para mí, incluso si no hacen la prueba más fácil. No es el hecho de que una serie barajar algoritmo requiere cualquier estado del todo distinta de la matriz que está barajando un detalle de implementación que el llamante no debería tener que preocuparse? ¿No el lugar correcto para obtener esta información de forma implícita, posiblemente de un producto único subproceso local?

¿Fue útil?

Solución

Sí, que se rompe encapsulación . Al igual que con la mayoría de las decisiones de diseño de software, esto es un equilibrio entre dos fuerzas opuestas. Si encapsular el RNG luego de hacer difícil cambiar de una prueba de unidad. Si usted lo hace un parámetro luego de hacer más fácil para un usuario para cambiar el generador de números aleatorios (y potencialmente se equivocan).

Mi preferencia personal es hacer que sea fácil de probar, a continuación, proporcionar una implementación por defecto (un constructor predeterminado que crea su propio generador de números aleatorios, en este caso particular) y una buena documentación para el usuario final. Adición de un método con la firma

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

que crea un Random utilizando la hora actual del sistema como su semilla se haría cargo de la mayoría de los casos de uso normales de este método. El método original

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

podría ser utilizado para la prueba (pasa en un objeto Random con una semilla conocido) y también en aquellos casos raros en los que un usuario decide que necesitan un RNG criptográficamente seguro. La implementación de un parámetro debe llamar a este método.

Otros consejos

No creo que se rompe la encapsulación. El único estado de la matriz es los datos en sí - y "una fuente de aleatoriedad" es esencialmente un servicio. ¿Por qué una matriz, naturalmente, tienen una fuente de aleatoriedad asociado? ¿Por qué habría que ser un producto único? ¿Qué hay de diferentes situaciones que tienen diferentes requisitos - por ejemplo, la velocidad vs aleatoriedad criptográficamente seguro? Hay una razón por la java.util.Random tiene una subclase SecureRandom :) Tal vez no importa si los resultados de la reproducción aleatoria son predecibles con mucho esfuerzo y observación - o tal vez lo hace. Eso dependerá del contexto, y eso es la información que el algoritmo aleatorio no debe preocuparse.

Una vez que comience a pensar en él como un servicio, no tiene sentido que se pasa como una dependencia.

Sí, podría obtenerlo de un producto único local de subprocesos (y de hecho voy a blog sobre exactamente que en los próximos días), pero en general me codificarlo para que el < em> persona que llama llega a tomar esa decisión.

Uno de los beneficios de la "aleatoriedad como un servicio" concepto es que hace que la repetibilidad - si usted tiene una prueba que falla, puede pasar en un Random con una semilla específica y sabe que siempre obtendrá la misma resultados, lo que hace más fácil la depuración.

Por supuesto, siempre existe la opción de hacer el Random opcional -. Utilizar un producto único local de subprocesos como defecto si la persona que llama no proporciona su propia

No creo que esto viola la encapsulación.

Su ejemplo

Yo diría que ser capaz de proporcionar un generador de números aleatorios es una característica de la clase. obviamente me gustaría proporcionar un método que no requiere de él, pero puedo ver tiempos donde puede ser útil ser capaz de duplicar la asignación al azar.

¿Qué pasa si la matriz shuffler era parte de un juego que utiliza el generador de números aleatorios para la generación de nivel. Si un usuario desea guardar el nivel y jugar de nuevo más tarde, puede ser más eficiente para almacenar la semilla de números aleatorios.

Caso general

clases simples que tienen una sola tarea como esta por lo general no tienen que preocuparse por la divulgación de su funcionamiento interno. Lo que encapsulan la lógica de la tarea, no los elementos requeridos por esa lógica.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top