Supongamos que tengo un objeto personalizado, Estudiante :
public class Student{
public int _id;
public String name;
public int age;
public float score;
}
Y una clase, Window , que se usa para mostrar información de un Estudiante :
public class Window{
public void showInfo(Student student);
}
Parece bastante normal, pero descubrí que Window no es fácil de probar individualmente, porque necesita un objeto real de Student para llamar a la función. Así que trato de modificar showInfo para que no acepte un objeto Student directamente:
public void showInfo(int _id, String name, int age, float score);
para que sea más fácil probar Windows individualmente:
showInfo(123, "abc", 45, 6.7);
Pero descubrí que la versión modificada tiene otros problemas:
Modificar estudiante (por ejemplo: agregar nuevas propiedades) requiere modificar la firma del método de showInfo
Si Student tuviera muchas propiedades, la firma del método de Student sería muy larga.
Entonces, usando objetos personalizados como parámetro o acepte cada propiedad en los objetos como parámetro, ¿cuál es más fácil de mantener?

showInforequiere una cadena real, un flotador real y dos entradas reales. ¿Cómo esStringmejor proporcionar unStudentobjeto real que proporcionar un objeto real ?intparámetros. Desde el sitio de la llamada, no hay verificación de que realmente los esté pasando en el orden correcto. ¿Qué pasa si intercambiasidyage, ofirstNameylastName? Está introduciendo un posible punto de falla que puede ser muy difícil de detectar hasta que explote en su cara, y lo está agregando en cada sitio de llamada .showForm(bool, bool, bool, bool, int)método - Me encantan esos ...Respuestas:
El uso de un objeto personalizado para agrupar parámetros relacionados es en realidad un patrón recomendado. Como refactorización, se llama Introducir objeto de parámetro .
Tu problema yace en otra parte. Primero, genérico no
Windowdebe saber nada sobre el estudiante. En cambio, debe tener algún tipo deStudentWindowconocimiento que solo se muestreStudents. En segundo lugar, no hay absolutamente ningún problema en crear unaStudentinstancia para probarStudentWindowsiempre yStudentcuando no contenga ninguna lógica compleja que pueda complicar drásticamente la pruebaStudentWindow. Si tiene esa lógica, entoncesStudentdebería preferirse hacer una interfaz y burlarse de ella.fuente
Studentagrupación tiene sentido y es probable que surja en otras áreas de la aplicación.Student, sería un Objeto completo de conservacióna.b.csi su método tomaa. Si su método llega al punto en el que necesita tener aproximadamente más de 4 parámetros o 2 niveles de profundidad de acceso a la propiedad, probablemente sea necesario tenerlo en cuenta. También tenga en cuenta que esta es una directriz, como todas las demás, requiere discreción del usuario. No lo sigas a ciegas.Tu dices que es
Pero solo puede crear un objeto de estudiante para pasar a su ventana:
No parece mucho más complejo llamar.
fuente
Studentrefiere a aUniversity, que se refiere a muchosFacultysyCampuss, conProfessorsyBuildings, ninguno de los cualesshowInforealmente usa, pero no ha definido ninguna interfaz que permita que las pruebas "sepan" eso y suministren solo al estudiante relevante datos, sin construir toda la organización. El ejemploStudentes un objeto de datos simple y, como usted dice, las pruebas deberían estar felices de trabajar con él.En términos simples:
Editar:
Como @ Tom.Bowen89 afirma que no es mucho más complejo probar el método showInfo:
fuente
fuente
Steve McConnell en Code Complete abordó este mismo problema, discutiendo los beneficios y los inconvenientes de pasar objetos a métodos en lugar de usar propiedades.
Perdóname si me equivoco con algunos detalles, estoy trabajando de memoria ya que ha pasado más de un año desde que tuve acceso al libro:
Llega a la conclusión de que es mejor no usar un objeto, sino que solo envía aquellas propiedades absolutamente necesarias para el método. El método no debería tener que saber nada sobre el objeto fuera de las propiedades que usará como parte de sus operaciones. Además, con el tiempo, si alguna vez se cambia el objeto, esto podría tener consecuencias no deseadas en el método que usa el objeto.
También abordó que si terminas con un método que acepta muchos argumentos diferentes, entonces eso es probablemente una señal de que el método está haciendo demasiado y debería dividirse en más métodos más pequeños.
Sin embargo, a veces, a veces, realmente necesitas muchos parámetros. El ejemplo que da sería un método que construye una dirección completa, utilizando muchas propiedades de dirección diferentes (aunque esto podría obtenerse utilizando una matriz de cadenas cuando lo piensa).
fuente
Studenten este caso). Y así es como las pruebas informan el diseño , abrazando completamente la respuesta con más votos y manteniendo la integridad del diseño.Es mucho más fácil escribir y leer pruebas si pasa todo el objeto:
Para comparacion,
la línea podría escribirse, si pasa valores por separado, como:
donde la llamada al método real está enterrada en algún lugar como
Para ir al grano, que no puede poner la llamada al método real en la prueba es una señal de que su API es mala.
fuente
Debes pasar lo que tiene sentido, algunas ideas:
Más fácil de probar. Si los objetos necesitan ser editados, ¿qué requiere la menor refactorización? ¿Es útil reutilizar esta función para otros fines? ¿Cuál es la menor cantidad de información que necesito dar a esta función para cumplir su propósito? (Al dividirlo, puede permitirle volver a usar este código, tenga cuidado de no caer en el agujero de diseño para hacer que esta función funcione y luego cuele todo para usar este objeto exclusivamente).
Todas estas reglas de programación son solo guías para que pienses en la dirección correcta. Simplemente no construya una bestia de código: si no está seguro y solo necesita continuar, elija una dirección / suya o una sugerencia aquí, y si llega a un punto en el que piensa 'oh, debería haberlo hecho así way '- probablemente puedas volver y refactorizarlo con bastante facilidad. (Por ejemplo, si tiene la clase Profesor, solo necesita la misma propiedad establecida que Estudiante, y cambia su función para aceptar cualquier objeto del formulario Persona)
Me inclinaría más a mantener el objeto principal que se pasa, porque la forma en que codifique va a explicar más fácilmente lo que está haciendo esta función.
fuente
Una ruta común alrededor de esto es insertar una interfaz entre los dos procesos.
Esto se vuelve un poco complicado a veces, pero las cosas se ponen un poco más ordenadas en Java si usa una clase interna.
Luego puede probar la
Windowclase simplemente dándole unHasInfoobjeto falso .Sospecho que este es un ejemplo del Patrón Decorador .
Adicional
Parece haber cierta confusión causada por la simplicidad del código. Aquí hay otro ejemplo que puede demostrar mejor la técnica.
fuente
StudentyStringaquí para el tipo de retorno es solo para demostración. Con toda probabilidad habría parámetros adicionales agetInfocomo elPaneseñalar a si el dibujo. El concepto aquí es pasar componentes funcionales como decoradores del objeto original .HasInfoobjetos.StudentSabe ser uno.getInfovuelta al vacío, pásalaPanepara dibujar, entonces la implementación (en laStudentclase) se acopla repentinamente al swing o lo que sea que estés usando. Si hace que devuelva alguna cadena y tome 0 parámetros, su interfaz de usuario no sabrá qué hacer con la cadena sin suposiciones mágicas y acoplamiento implícito. Si hace que engetInforealidad devuelva algún modelo de vista con propiedades relevantes, entonces suStudentclase está nuevamente acoplada a la lógica de presentación. No creo que ninguna de estas alternativas sea deseableYa tiene muchas buenas respuestas, pero aquí hay algunas sugerencias más que pueden permitirle ver una solución alternativa:
Su ejemplo muestra un Estudiante (claramente un objeto modelo) que se pasa a una Ventana (aparentemente un objeto a nivel de vista). Un objeto de controlador o presentador intermediario puede ser beneficioso si aún no tiene uno, lo que le permite aislar su interfaz de usuario de su modelo. El controlador / presentador debe proporcionar una interfaz que se pueda usar para reemplazarlo para las pruebas de IU, y debe usar interfaces para referirse a los objetos del modelo y ver los objetos para poder aislarlo de ambos para las pruebas. Es posible que deba proporcionar alguna forma abstracta de crearlos o cargarlos (por ejemplo, objetos Factory, objetos de repositorio o similares).
Transferir partes relevantes de los objetos de su modelo a un Objeto de transferencia de datos es un enfoque útil para interactuar cuando su modelo se vuelve demasiado complejo.
Puede ser que su estudiante viole el Principio de segregación de interfaz. Si es así, podría ser beneficioso dividirlo en múltiples interfaces con las que sea más fácil trabajar.
Lazy Loading puede facilitar la construcción de gráficos de objetos grandes.
fuente
Esta es realmente una pregunta decente. El problema real aquí es el uso del término genérico "objeto", que puede ser un poco ambiguo.
Generalmente, en un lenguaje OOP clásico, el término "objeto" ha llegado a significar "instancia de clase". Las instancias de clase pueden ser bastante pesadas: propiedades públicas y privadas (y las intermedias), métodos, herencia, dependencias, etc. Realmente no querría usar algo así para simplemente pasar algunas propiedades.
En este caso, está utilizando un objeto como contenedor que simplemente contiene algunas primitivas. En C ++, los objetos como estos se conocían como
structs(y todavía existen en lenguajes como C #). De hecho, las estructuras se diseñaron exactamente para el uso del que hablas: agruparon objetos relacionados y primitivas cuando tenían una relación lógica.Sin embargo, en los lenguajes modernos, realmente no hay diferencia entre una estructura y una clase cuando se escribe el código , por lo que está bien usar un objeto. (Detrás de escena, sin embargo, hay algunas diferencias que debe tener en cuenta; por ejemplo, una estructura es un tipo de valor, no un tipo de referencia). Básicamente, siempre que mantenga su objeto simple, será fácil Para probar manualmente. Sin embargo, los lenguajes y herramientas modernos le permiten mitigar esto un poco (a través de interfaces, marcos de imitación, inyección de dependencias, etc.)
fuente
Student) en modelos de vista (StudentInfooStudentInfoViewModeletc.), pero podría no ser necesario.