Estoy comenzando un proyecto de grupo escolar en Java, usando Swing. Es una interfaz gráfica de usuario sencilla en la aplicación de escritorio de la base de datos.
El profesor nos dio el código del proyecto del año pasado para que pudiéramos ver cómo hace las cosas. Mi impresión inicial es que el código es mucho más complicado de lo que debería ser, pero imagino que los programadores a menudo piensan esto cuando miran el código que no acaban de escribir.
Espero encontrar razones por las cuales su sistema es bueno o malo. (Le pregunté al profesor y él dijo que vería más tarde por qué es mejor, lo que no me satisface)
Básicamente, para evitar cualquier acoplamiento entre sus objetos persistentes, modelos (lógica de negocios) y vistas, todo se hace con cadenas. Los objetos persistentes que se almacenan en la base de datos son tablas hash de cadenas, y los modelos y vistas se "suscriben" entre sí, proporcionando claves de cadena para los "eventos" a los que se suscriben.
Cuando se activa un evento, la vista o modelo envía una cadena a todos sus suscriptores que deciden qué hacer para ese evento. Por ejemplo, en uno de los métodos de escucha de acción de vistas (creo que esto simplemente establece el bicycleMakeField en el objeto persistente):
else if(evt.getSource() == bicycleMakeField)
{
myRegistry.updateSubscribers("BicycleMake", bicycleMakeField.getText());
}
Esa llamada finalmente llega a este método en el modelo del vehículo:
public void stateChangeRequest(String key, Object value) {
... bunch of else ifs ...
else
if (key.equals("BicycleMake") == true)
{
... do stuff ...
El profesor dice que esta forma de hacer cosas es más extensible y mantenible que tener la vista simplemente llamando a un método en un objeto de lógica de negocios. Él dice que no hay acoplamiento entre las vistas y los modelos porque no saben de la existencia de los demás.
Creo que este es un tipo de acoplamiento peor, porque la vista y el modelo tienen que usar las mismas cadenas para funcionar. Si elimina una vista o modelo, o comete un error tipográfico en una cadena, no obtendrá errores de compilación. También hace que el código sea mucho más largo de lo que creo que debe ser.
Quiero discutir esto con él, pero él usa su experiencia en la industria para contrarrestar cualquier argumento que yo, el estudiante inexperto, pueda hacer. ¿Hay alguna ventaja en su enfoque que me estoy perdiendo?
Para aclarar, quiero comparar el enfoque anterior, con tener la vista obviamente acoplada al modelo. Por ejemplo, puede pasar el objeto del modelo del vehículo a la vista y luego, para cambiar la "marca" del vehículo, haga lo siguiente:
vehicle.make = bicycleMakeField.getText();
Esto reduciría 15 líneas de código que actualmente SÓLO se usan para configurar la marca del vehículo en un solo lugar, en una sola línea de código legible. (Y dado que este tipo de operación se realiza cientos de veces en toda la aplicación, creo que sería una gran victoria para la legibilidad y la seguridad).
Actualizar
El líder de mi equipo y yo reestructuramos el marco de la forma en que queríamos hacerlo usando la escritura estática, informamos al profesor y terminamos ofreciéndole una demostración. Es lo suficientemente generoso como para dejarnos usar nuestro marco siempre y cuando no le pidamos ayuda, y si podemos mantener al resto de nuestro equipo al día, lo que nos parece justo.
Respuestas:
El enfoque que propone su profesor se describe mejor como mecanografiado en cadena y es incorrecto en casi todos los niveles.
El acoplamiento se reduce mejor en la inversión de dependencia , que lo hace mediante un envío polimórfico, en lugar de cablear varios casos.
fuente
Tu profesor lo está haciendo mal . Está tratando de desacoplar completamente la vista y el modelo forzando la comunicación a viajar a través de una cadena en ambas direcciones (la vista no depende del modelo y el modelo no depende de la vista) , lo que anula totalmente el propósito del diseño orientado a objetos y MVC. Parece que, en lugar de escribir clases y diseñar una arquitectura basada en OO, está escribiendo módulos dispares que simplemente responden a mensajes basados en texto.
Para ser algo justo con el profesor, está tratando de crear en Java lo que se parece mucho a la interfaz común .NET llamada
INotifyPropertyChanged
, que notifica a los suscriptores de los eventos de cambio mediante la aprobación de cadenas que especifican qué propiedad ha cambiado. Al menos en .NET, esta interfaz se usa principalmente para comunicarse desde un modelo de datos para ver objetos y elementos GUI (enlace).Si se hace bien , tomar este enfoque puede tener algunos beneficios¹:
events
pero en Java tendría que crear clases u objetos y escribir código de suscripción / cancelación de suscripción para cada evento.Entonces, en resumen (y para responder a su pregunta), se puede hacer, pero el enfoque que está tomando su profesor tiene la culpa de no permitir al menos una dependencia unidireccional entre la Vista y el Modelo. Simplemente no es práctico, demasiado académico, y no es un buen ejemplo de cómo usar las herramientas disponibles.
¹ Busque en Google para
INotifyPropertyChanged
encontrar un millón de formas en que las personas intentan evitar el uso de cuerdas mágicas al implementarlo.fuente
enum
s (opublic static final String
s) deben usarse en lugar de cadenas mágicas.Tu profesor no entiende OO . Por ejemplo, tener una clase de vehículo concreto?
¿Y que esta clase entienda la marca de una bicicleta?
El vehículo debe ser abstracto y debe haber una subclase concreta llamada Bike. Jugaría según sus reglas para obtener una buena calificación y luego olvidaría su enseñanza.
fuente
Creo que tienes un buen punto, las cuerdas mágicas son malas. Alguien en mi equipo tuvo que depurar un problema causado por cadenas mágicas hace un par de semanas (pero fue en su propio código que escribieron, así que mantuve la boca cerrada). Y sucedió ... en la industria !!
La ventaja de su enfoque es que podría ser más rápido codificar, especialmente para pequeños proyectos de demostración. Las desventajas son que es propenso a los errores tipográficos y cuanto más se usa la cadena, más posibilidades hay de que un código tipográfico arruine las cosas. Y si alguna vez desea cambiar una cadena mágica, refactorizar cadenas es más difícil que refactorizar variables, ya que las herramientas de refactorización también pueden tocar cadenas que contienen la cadena mágica (como una subcadena) pero no son la cadena mágica, y no deberían deben tocarse. Además, es posible que deba mantener un diccionario o un índice de cadenas mágicas para que los nuevos desarrolladores no comiencen a inventar nuevas cadenas mágicas con el mismo propósito, y no pierdan el tiempo buscando cadenas mágicas existentes.
En este contexto, parece que una enumeración podría ser mejor que las cadenas mágicas o incluso las constantes de cadena globales. Además, los IDE a menudo le brindarán algún tipo de asistencia de código (autocompletar, refactorizar, buscar todas las referencias, etc.) cuando use cadenas o enumeraciones constantes. Un IDE no ofrecerá mucha ayuda si usa cadenas mágicas.
fuente
Usar 'experiencia en la industria' es un argumento pobre. Su profesor necesita encontrar un argumento mejor que ese :-).
Como otros han dicho, el uso de cadenas mágicas ciertamente está mal visto, el uso de enumeraciones se considera mucho más seguro. Una enumeración tiene significado y alcance , las cuerdas mágicas no. Aparte de eso, la forma en que su profesor está desacoplando las preocupaciones se considera una técnica más antigua y más frágil que la utilizada en la actualidad.
Veo que @backtodos ha cubierto esto mientras respondía esto, así que simplemente agregaré mi opinión de que al usar la Inversión de control (de la cual la Inyección de dependencias es una forma, se ejecutará en el marco de Spring en la industria en poco tiempo. ..) se considera una forma más moderna de lidiar con este tipo de desacoplamiento.
fuente
Seamos bastante claros; existe inevitablemente cierto acoplamiento allí. El hecho de que haya un tema suscribible es un punto de acoplamiento, como lo es la naturaleza del resto del mensaje (como "cadena única"). Dado eso, la pregunta se convierte en si el acoplamiento es mayor cuando se realiza mediante cadenas o tipos. La respuesta a eso depende de si le preocupa el acoplamiento que se distribuye en el tiempo o el espacio: si los mensajes se van a preservar en un archivo antes de leerlos más tarde, o si se van a enviar a otro proceso (especialmente si eso no está escrito en el mismo idioma), el uso de cadenas puede hacer las cosas mucho más simples. La desventaja es que no hay verificación de tipo; los errores no se detectarán hasta el tiempo de ejecución (y a veces ni siquiera entonces).
Una estrategia de mitigación / compromiso para Java puede ser usar una interfaz escrita, pero donde esa interfaz escrita está en un paquete separado. Debe consistir solo en Java
interface
sy tipos de valores básicos (por ejemplo, enumeraciones, excepciones). No debe haber ningún implementaciones de interfaces en ese paquete. Luego, todos implementan contra eso y, si es necesario transmitir los mensajes de una manera compleja, una implementación particular de un delegado de Java puede usar cadenas mágicas según sea necesario. También hace que sea mucho más fácil migrar el código a un entorno más profesional como JEE u OSGi, y ayuda mucho a cosas pequeñas como las pruebas ...fuente
Lo que su profesor propone es el uso de "cuerdas mágicas". Si bien "combina libremente" las clases entre sí, lo que permite cambios más fáciles, es un antipatrón; las cadenas deben usarse MUY, MUY raramente para contener o controlar las instrucciones del código, y cuando tiene que suceder absolutamente, el valor de las cadenas que está utilizando para controlar la lógica debe definirse central y constantemente para que haya UNA autoridad sobre el valor esperado de cualquier cadena particular
La razón por la cual es muy simple; las cadenas no se comprueban en el compilador para determinar la sintaxis o la coherencia con otros valores (en el mejor de los casos, se verifica la forma adecuada con respecto a los caracteres de escape y otro formato específico del idioma dentro de la cadena). Puedes poner lo que quieras en una cadena. Como tal, puede obtener un algoritmo / programa irremediablemente roto para compilar, y no es hasta que se ejecuta que se produce un error. Considere el siguiente código (C #):
... todo este código se compila, primer intento, pero el error es obvio con una segunda mirada. Existen numerosos ejemplos de este tipo de programación, y todos están sujetos a este tipo de error, INCLUSO SI define cadenas como constantes (porque las constantes en .NET se escriben en el manifiesto de cada biblioteca en la que se usan, lo que debe entonces todos se recompilarán cuando se cambie el valor definido para que el valor cambie "globalmente"). Como el error no se detecta en tiempo de compilación, debe detectarse durante las pruebas en tiempo de ejecución, y eso solo está garantizado con una cobertura de código del 100% en pruebas unitarias con ejercicio de código adecuado, que generalmente solo se encuentra en la prueba de fallas más absoluta , sistemas en tiempo real.
fuente
En realidad, esas clases todavía están estrechamente unidas. ¡Excepto que ahora están estrechamente acoplados de tal manera que el compilador no puede decirte cuándo se rompen las cosas!
Si alguien cambia "BicycleMake" a "BicyclesMake", nadie descubrirá que las cosas están rotas hasta el tiempo de ejecución.
Los errores de tiempo de ejecución son mucho más costosos de corregir que los errores de tiempo de compilación: esto es solo todo tipo de maldad.
fuente