Design Patterns in Java: Advanced Examples and Implementation

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Advanced Design Patterns in Java: From Theory to Complex Examples



Design patterns are proven solutions to typical problems that arise during software development. While basic patterns (Singleton, Factory, Observer) are familiar to most Java developers, advanced patterns require a deep understanding of architecture and the ability to apply them in complex business scenarios. In this article, we will break down three powerful patterns: Visitor, Command, and State — with real-world Java examples that will help you write more flexible and maintainable code.



1. Visitor Pattern: Separating Algorithms from Data Structures



Purpose: Allows adding new operations to objects of different classes without modifying the classes themselves. It is ideal for working with complex hierarchies where different actions need to be performed depending on the object type.



Problem: Imagine a document management system with classes TextDocument, ImageDocument, and SpreadsheetDocument. You need to implement export to PDF, HTML, and TXT. Without Visitor, each new export format would require changes to all document classes.



Solution with Visitor:



// 1. Element interface (document)interface DocumentElement {    void accept(DocumentVisitor visitor);}

// 2. Concrete elementsclass 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. Visitor interfaceinterface DocumentVisitor { void visit(TextDocument doc); void visit(ImageDocument doc); void visit(SpreadsheetDocument doc);}

// 4. Concrete visitor — HTML exportclass 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. Client codepublic 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()); }}


Key advantage: To add a new format (e.g., JSON), you only need to create a new class JsonExporter implements DocumentVisitor — none of the document classes are changed.



2. Command Pattern: C

Blogs

Book Recommendations