Contact Management App enforces a strict Model-View-Controller separation using Java package boundaries. TheDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/efrain-svg/Potes_Freddy_ProgInterfacesG_U3/llms.txt
Use this file to discover all available pages before exploring further.
modelo package contains classes with no Swing imports, the vista package owns all Swing component construction, and the controlador package is the only place where listeners are attached and business rules are applied. This page explains how each layer is defined and how they connect at runtime.
The three layers
Model
modelo/persona.java — entitymodelo/personaDAO.java — data accessNo Swing imports. Pure data and file I/O.
View
vista/ventana.java — main windowBuilds and lays out all Swing components. Exposes them as public fields. Contains no listeners or business logic.
Controller
controlador/logica_ventana.javaImplements
ActionListener, ListSelectionListener, ItemListener. Wires all events, manages concurrency, calls the DAO.Model layer
The model layer consists of two classes that have no knowledge of the UI.persona.java is a plain entity that holds a contact’s data and knows how to serialize itself:
datosContacto()— returns a semicolon-delimited string for CSV storagecomoFilaTabla()— returns anObject[]that aJTablemodel can consume directly
personaDAO.java encapsulates all file-system interaction:
- Reads and writes
c:/gestionContactos/datosContactos.csv - Handles both the legacy 5-column format and the current 6-column format
- Provides export overloads for custom column headers
- Uses
normalizarCategoria()to map multilingual display names to stable category codes
javax.swing or java.awt. If the storage format changes to a database in the future, only personaDAO needs to change.
View layer
ventana.java is responsible for constructing the entire UI and nothing else. Its main() method is the application entry point:
ventana.java
construirTabContactos()— assembles the Contacts tab: form fields, action buttons, filter bar,JTable, and status bar usingBorderLayoutandGridBagLayoutconstruirTabEstadisticas()— assembles the Statistics tab: summary stat cards,BarChartPanel, andPieChartPanel
Public field exposure
Rather than generating getter methods for every interactive component,ventana declares them as public fields. This is intentional: all event wiring is centralized in the controller, so the view only needs to make components reachable.
ventana.java
The view never attaches a listener to any of these components. That responsibility belongs exclusively to the controller.
Controller layer
logica_ventana.java receives a ventana instance (called delegado) in its constructor and uses it to reach every public field. It also holds the DAO, the i18n helper, the contact list, and all concurrency primitives.
logica_ventana.java
Event wiring: configurarEventos()
All listeners are attached in a single method called during construction. The view’s public fields are used directly:
logica_ventana.java
| Method | Responsibility |
|---|---|
configurarTablaYFiltro() | Attaches TableRowSorter, DocumentListener for live search, and mouse listener for double-click edit |
configurarAtajos() | Registers InputMap/ActionMap bindings for Ctrl+S (save), Ctrl+N (new), Delete, Ctrl+E (edit), Ctrl+F (focus filter) |
configurarMenuContextual() | Builds right-click popup menu with edit and delete actions |
aplicarIdioma(String) | Fetches translated strings from I18n and updates all component labels without rebuilding the UI |
CRUD methods
The controller owns all business operations:Load contacts
cargarContactosRegistrados() — launches a SwingWorker that calls dao.leerArchivo() on a background thread, then populates modeloTabla on the EDT in done().Add a contact
agregarContacto() — reads form fields from delegado, constructs a persona, calls validarContactoAsync() for a duplicate check, then calls dao.escribirArchivo() and refreshes the table.Edit a contact
modificarContactoSeleccionado() — reads the selected row, pre-fills form fields via delegado, lets the user edit, then calls dao.actualizarContactos(contactos) which rewrites the entire file.Delete a contact
eliminarSeleccionado() — removes the entry from the in-memory list and calls dao.actualizarContactos(contactos) to persist the deletion.Async search: solicitarBusquedaAsync()
The search field uses an AtomicInteger sequence number to discard stale results from previous keystrokes:
logica_ventana.java
Benefits of this separation
| Benefit | How it is achieved |
|---|---|
| Testable model | persona and personaDAO have no Swing dependencies and can be unit-tested without a display |
| Single place for event wiring | All listeners are added in configurarEventos() — no listener logic scattered across UI builder methods |
| UI rebuild without logic changes | ventana can be completely redesigned as long as its public field names remain stable |
| Locale switching at runtime | aplicarIdioma() updates labels via I18n without reconstructing any component |
| Responsive UI under load | All blocking operations use SwingWorker or ExecutorService, never blocking the EDT |
Related pages
Architecture overview
Package structure, technology stack, and the full list of key design decisions.
Contact data model
persona fields, constructors, CSV serialization, and personaDAO method reference.