Primero: nuestro programa funciona
No estamos corrigiendo un error de sintaxis ni un botón roto. Estamos entrando en otro tipo de problema: cómo organizar un programa que crece.
En el proyecto actual, Main crea la lista de productos y la ventana, registra las acciones de los botones, obtiene los datos escritos por el usuario, convierte esos datos, crea un Producto y lo agrega a la colección.
public static void main(String[] args) {
ArrayList<Producto> listaProductos =
new ArrayList<Producto>();
Producto_Vista ventana = new Producto_Vista();
ventana.setVisible(true);
ventana.listenerCancelar(e ->
ventana.limpiarCampos());
ventana.listenerAgregar(e -> {
long codigo = Long.parseLong(ventana.getTxtCodigo());
String nombre = ventana.getTxtNombre();
double precio = Double.parseDouble(ventana.getTxtPrecio());
int stock = Integer.parseInt(ventana.getTxtStock());
Producto p = new Producto(codigo, nombre, precio, stock);
listaProductos.add(p);
JOptionPane.showMessageDialog(ventana, listaProductos);
});
ventana.listenerEliminar(e -> {
JOptionPane.showConfirmDialog(ventana, "¿Está seguro?");
});
}
¿Cuántos trabajos está haciendo Main?
Leamos el código por responsabilidades, no por líneas.
Mantiene el
ArrayList<Producto>.Crea y muestra la ventana.
Decide qué ocurre al pulsar botones.
Lee los datos de los
JTextField.Transforma texto en
long, double e int.Construye objetos
Producto.Agrega elementos a la colección.
Muestra mensajes con
JOptionPane.El problema todavía es pequeño… porque la aplicación todavía es pequeña
Imaginemos que continuamos agregando funcionalidades sin cambiar la organización actual.
Si cada nueva función termina dentro de Main, ocurre algo previsible: cualquier cambio obliga a volver siempre al mismo lugar.
Una clase debería tener una responsabilidad principal clara
En diseño orientado a objetos aparece una regla muy útil: intentar que cada clase tenga una responsabilidad principal bien identificable.
Todo mezclado
Main arranca, escucha, valida, crea, guarda y muestra.
Un cambio en casi cualquier parte de la aplicación puede llevarnos a la misma clase.
Responsabilidades separadas
Cada componente resuelve un tipo de problema y colabora con los demás.
Los cambios quedan más localizados.
¿Esto tiene relación con SOLID?
Sí. La idea se relaciona con el Principio de Responsabilidad Única (SRP), la “S” de SOLID. Una formulación más precisa dice que una clase debería tener un motivo principal de cambio. Por ahora no necesitamos memorizar los cinco principios: nos alcanza con reconocer el problema que este principio intenta evitar.
Separar para poder cambiar
La modularidad consiste en organizar un sistema en partes con responsabilidades claras y relaciones controladas entre ellas.
Crear paquetes ayuda a ordenar físicamente los archivos, pero modularidad no significa solamente crear carpetas. Si dividimos el código en cinco paquetes pero todos dependen de todos, el problema continúa.
Dos conceptos que vamos a volver a encontrar
Antes de programar más, decidimos dónde debería vivir cada responsabilidad
La arquitectura de software nos ayuda a pensar cuáles son las partes principales de una aplicación, qué responsabilidad tiene cada una y cómo se comunican.
Las líneas punteadas representan componentes que todavía no construimos. Este es un mapa de llegada, no código para copiar ahora.
Un término opcional: “composition root”
En aplicaciones más grandes se llama composition root al lugar donde se crean y conectan los objetos principales. Nuestro Main se acercará a ese papel. No necesitamos usar este término para programar bien, pero explica por qué un Main pequeño puede seguir siendo importante.
No somos los primeros en encontrarnos con estos problemas
En programación aparecen problemas de diseño que se repiten. Un patrón describe una forma conocida de organizar una solución. No es un bloque de código que se copia sin pensar: es una idea que se adapta al problema concreto.
| Nivel | Qué organiza | Ejemplos |
|---|---|---|
| Patrones de diseño | Colaboraciones concretas entre clases u objetos. | Observer, Strategy, Factory. |
| Patrones / estilos arquitectónicos | La organización general de partes importantes de una aplicación. | MVC, arquitectura en capas. |
¿Qué vamos a utilizar nosotros?
En Tienda de Cómics construiremos una arquitectura en capas y, en la parte de interacción, tomaremos la separación de responsabilidades propia de MVC: una Vista que muestra, un Controller que coordina y componentes de negocio que resuelven operaciones.
No vamos a crear todas las capas de golpe
Cada componente aparecerá cuando el código nos muestre qué problema viene a resolver.
Problema: Main coordina demasiadas acciones.
Siguiente solución: ProductoController.
Problema: Controller empieza a acumular reglas y operaciones.
Solución: ProductoService.
Problema: los datos del ArrayList desaparecen al cerrar.
Solución: DAO + JDBC + base de datos.
La arquitectura no se aprende repitiendo ese dibujo. Se aprende entendiendo por qué cada flecha y cada componente terminaron siendo necesarios.
¿Qué tipo de componente debería hacerse cargo?
Elegí una opción. No estamos evaluando sintaxis: estamos pensando responsabilidades.
1. Cambiar el color y el texto del botón “Agregar”.
2. Recibir el clic en “Agregar” y coordinar qué debe ocurrir a continuación.
3. Decidir que un producto no puede guardarse con precio negativo.
4. Crear los componentes principales al iniciar el programa y conectarlos.
La pregunta ya cambió
Al principio preguntábamos:
Ahora podemos formular una pregunta de diseño:
Ese cambio de pregunta marca el paso de escribir funcionalidades aisladas a diseñar una aplicación que pueda crecer.
Micro-entrega de documentación
Antes de continuar, registrá en el cuaderno o documento del proyecto:
- al menos cuatro responsabilidades que hoy tiene
Main; - una explicación de dos o tres líneas de qué entendés por modularidad;
- un esquema simple del recorrido futuro:
Main → Controller → Service → DAO; - una frase que complete: “Main no debería hacer el trabajo de la aplicación; debería…”
Próximo material: vamos a crear ProductoController y trasladar allí la coordinación de eventos que hoy está dentro de Main, sin cambiar lo que el usuario ve.
