Patrones de diseño avanzados en Java: de la teoría a ejemplos complejos
Los patrones de diseño son soluciones probadas para problemas típicos que surgen durante el desarrollo de software. Si los patrones básicos (Singleton, Factory, Observer) son conocidos por la mayoría de los desarrolladores de Java, los patrones avanzados requieren una comprensión profunda de la arquitectura y la capacidad de aplicarlos en escenarios empresariales complejos. En este artículo, analizaremos tres patrones potentes: Visitor, Command y State — con ejemplos reales en Java que le ayudarán a escribir código más flexible y mantenible.
1. Patrón Visitor: separación de algoritmos de la estructura de datos
Propósito: Permite agregar nuevas operaciones para objetos de diferentes clases sin modificar las clases mismas. Es ideal para trabajar con jerarquías complejas donde se requieren realizar diferentes acciones según el tipo de objeto.
Problema: Imagine un sistema de gestión documental donde existen las clases TextDocument, ImageDocument y SpreadsheetDocument. Necesita implementar la exportación a PDF, HTML y TXT. Sin Visitor, cada nuevo formato de exportación requeriría modificar todas las clases de documentos.
Solución con Visitor:
// 1. Interfaz del elemento (documento)interface DocumentElement { void accept(DocumentVisitor visitor);}
// 2. Elementos concretosclass TextDocument implements DocumentElement { private String content; public TextDocument(String content) { this.content = content; } public String getContent() { return content; } @Override public void accept(DocumentVisitor visitor) { visitor.visit(this); }}
class ImageDocument implements DocumentElement { private byte[] imageData; public ImageDocument(byte[] data) { this.imageData = data; } public byte[] getImageData() { return imageData; } @Override public void accept(DocumentVisitor visitor) { visitor.visit(this); }}
// 3. Interfaz del visitanteinterface DocumentVisitor { void visit(TextDocument doc); void visit(ImageDocument doc); void visit(SpreadsheetDocument doc);}
// 4. Visitante concreto — exportación a HTMLclass HtmlExporter implements DocumentVisitor { private StringBuilder sb = new StringBuilder(); @Override public void visit(TextDocument doc) { sb.append("<html><body><p>") .append(doc.getContent()) .append("</p></body></html>"); } @Override public void visit(ImageDocument doc) { sb.append("<html><body><img src='data:image/png;base64,") .append(Base64.getEncoder().encodeToString(doc.getImageData())) .append("'/></body></html>"); } @Override public void visit(SpreadsheetDocument doc) { sb.append("<html><body><table>...</table></body></html>"); } public String getResult() { return sb.toString(); }}
// 5. Código clientepublic class DocumentSystem { public static void main(String[] args) { List<DocumentElement> documents = Arrays.asList( new TextDocument("Hello World"), new ImageDocument(new byte[]{1,2,3}) ); HtmlExporter exporter = new HtmlExporter(); for (DocumentElement doc : documents) { doc.accept(exporter); } System.out.println(exporter.getResult()); }}Ventaja clave: Para agregar un nuevo formato (por ejemplo, JSON), basta con crear una nueva clase JsonExporter implements DocumentVisitor — ninguna de las clases de documentos se modifica.