Main coordina; ProductoVista sabe mostrarse
ProductoVista
- Crea y organiza componentes.
- Permite leer los campos.
- Sabe limpiar sus propios campos.
- Sabe convertir una lista de productos en filas de la tabla.
- Permite registrar listeners.
Main (por ahora)
- Crea la vista.
- Mantiene el
ArrayList<Producto>. - Decide qué hacer ante cada evento.
- Agrega y elimina productos.
- Decide cuándo refrescar y cuándo limpiar.
La Vista necesita una pequeña API pública
El modelo de la tabla pasa a ser atributo
private JTable tablaProductos; private DefaultTableModel modeloTabla;
Leer datos sin exponer los JTextField
public String getCodigo() {
return txtCodigo.getText();
}
public String getNombre() {
return txtNombre.getText();
}
public String getPrecio() {
return txtPrecio.getText();
}
public String getStock() {
return txtStock.getText();
}
Limpiar el formulario
public void limpiarCampos() {
txtCodigo.setText("");
txtNombre.setText("");
txtPrecio.setText("");
txtStock.setText("");
txtCodigo.requestFocusInWindow();
}
Registrar listeners
public void listenerAceptar(ActionListener listener) {
btnAceptar.addActionListener(listener);
}
public void listenerEliminar(ActionListener listener) {
btnEliminar.addActionListener(listener);
}
public void listenerCancelar(ActionListener listener) {
btnCancelar.addActionListener(listener);
}
listenerAceptar, listenerEliminar y listenerCancelar. lsnAceptar también funcionaría, pero la versión completa es más clara para aprender.Cancelar: comprobar el circuito más simple
vista.listenerCancelar(e -> {
vista.limpiarCampos();
});
Main no conoce txtCodigo, txtNombre, etc. Solo le pide a la Vista que se limpie.
El ArrayList vive en Main, por ahora
ArrayList<Producto> productos = new ArrayList<>(); ProductoVista vista = new ProductoVista();
El ArrayList será la fuente de verdad provisional. La tabla no contiene “los productos reales”: solo los representa.
Acción de Aceptar
vista.listenerAceptar(e -> {
String codigo = vista.getCodigo().trim();
String nombre = vista.getNombre().trim();
double precio =
Double.parseDouble(vista.getPrecio());
int stock =
Integer.parseInt(vista.getStock());
Producto producto =
new Producto(codigo, nombre, precio, stock);
productos.add(producto);
vista.actualizarTabla(productos);
vista.limpiarCampos();
});
ProductoVista sabe transformar Productos en filas
public void actualizarTabla(List<Producto> productos) {
modeloTabla.setRowCount(0);
for (Producto producto : productos) {
Object[] fila = {
producto.getCodigo(),
producto.getNombre(),
producto.getPrecio(),
producto.getStock()
};
modeloTabla.addRow(fila);
}
}
ArrayList no avisa a la tabla. Nosotros llamamos a actualizarTabla(productos). Lo automático ocurre entre DefaultTableModel y JTable.Relación con Observer
La llamada desde Main a actualizarTabla() es explícita, así que todavía no estamos usando Observer para nuestra colección. Sin embargo, la relación entre TableModel y JTable sí utiliza un mecanismo de notificación por eventos relacionado con ese patrón.
La Vista informa qué fila seleccionó el usuario
public int getFilaSeleccionada() {
return tablaProductos.getSelectedRow();
}
vista.listenerEliminar(e -> {
int fila = vista.getFilaSeleccionada();
if (fila >= 0) {
productos.remove(fila);
vista.actualizarTabla(productos);
vista.limpiarCampos();
}
});
Main completo en esta etapa
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<Producto> productos =
new ArrayList<>();
ProductoVista vista =
new ProductoVista();
vista.listenerCancelar(e -> {
vista.limpiarCampos();
});
vista.listenerAceptar(e -> {
String codigo = vista.getCodigo().trim();
String nombre = vista.getNombre().trim();
double precio =
Double.parseDouble(vista.getPrecio());
int stock =
Integer.parseInt(vista.getStock());
Producto producto =
new Producto(
codigo,
nombre,
precio,
stock
);
productos.add(producto);
vista.actualizarTabla(productos);
vista.limpiarCampos();
});
vista.listenerEliminar(e -> {
int fila = vista.getFilaSeleccionada();
if (fila >= 0) {
productos.remove(fila);
vista.actualizarTabla(productos);
vista.limpiarCampos();
}
});
vista.actualizarTabla(productos);
vista.setVisible(true);
}
}
| Situación | Main decide | ProductoVista hace |
|---|---|---|
| Cancelar | Hay que limpiar | Limpia sus campos |
| Aceptar | Crea y agrega Producto | Entrega datos, muestra lista y limpia |
| Eliminar | Quita del ArrayList | Entrega fila, muestra lista y limpia |
| Refrescar | Decide cuándo | Transforma productos en filas |
Main está creciendo… y eso es intencional
Ahora podemos ver el circuito completo sin esconderlo detrás de una arquitectura nueva:
Cuando este circuito esté claro, el siguiente problema aparecerá solo: Main estará acumulando demasiadas responsabilidades. Ahí tendrá sentido introducir ProductoController y trasladar allí la coordinación que hoy está en Main.