362 lines
14 KiB
Markdown
362 lines
14 KiB
Markdown
# GoF Design Patterns in Java
|
|
|
|
Complete runnable Java 25 implementations of all 23 Gang of Four design patterns.
|
|
Each pattern has a dedicated article at [ankurm.com](https://ankurm.com/gof-design-patterns-java/)
|
|
with a UML diagram, step-by-step explanation, and console output.
|
|
|
|
## Structure
|
|
|
|
```
|
|
design-patterns/
|
|
├── 01-creational/
|
|
│ ├── factory-method/
|
|
│ ├── abstract-factory/
|
|
│ ├── builder/
|
|
│ ├── prototype/
|
|
│ └── singleton/
|
|
├── 02-structural/
|
|
│ ├── adapter/
|
|
│ ├── bridge/
|
|
│ ├── composite/
|
|
│ ├── decorator/
|
|
│ ├── facade/
|
|
│ ├── flyweight/
|
|
│ └── proxy/
|
|
└── 03-behavioral/
|
|
├── chain-of-responsibility/
|
|
├── command/
|
|
├── interpreter/
|
|
├── iterator/
|
|
├── mediator/
|
|
├── memento/
|
|
├── observer/
|
|
├── state/
|
|
├── strategy/
|
|
├── template-method/
|
|
└── visitor/
|
|
```
|
|
|
|
## Prerequisites
|
|
|
|
- Java 25+ (Eclipse Temurin recommended)
|
|
- No build tool required — plain `javac` / `java`
|
|
|
|
## Run any pattern
|
|
|
|
```bash
|
|
# Linux / macOS / Git Bash (Windows)
|
|
javac 03-behavioral/strategy/*.java -d out/strategy
|
|
java -cp out/strategy strategy.Main
|
|
```
|
|
|
|
```cmd
|
|
REM Windows Command Prompt
|
|
javac 03-behavioral\strategy\*.java -d out\strategy
|
|
java -cp out\strategy strategy.Main
|
|
```
|
|
|
|
## Articles
|
|
|
|
| Pattern | Category | Article |
|
|
|---------|----------|---------|
|
|
| Factory Method | Creational | https://ankurm.com/factory-method-design-pattern-java/ |
|
|
| Abstract Factory | Creational | https://ankurm.com/abstract-factory-design-pattern-java/ |
|
|
| Builder | Creational | https://ankurm.com/builder-design-pattern-java/ |
|
|
| Prototype | Creational | https://ankurm.com/prototype-design-pattern-java/ |
|
|
| Singleton | Creational | https://ankurm.com/singleton-design-pattern-java/ |
|
|
| Adapter | Structural | https://ankurm.com/adapter-design-pattern-java/ |
|
|
| Bridge | Structural | https://ankurm.com/bridge-design-pattern-java/ |
|
|
| Composite | Structural | https://ankurm.com/composite-design-pattern-java/ |
|
|
| Decorator | Structural | https://ankurm.com/decorator-design-pattern-java/ |
|
|
| Facade | Structural | https://ankurm.com/facade-design-pattern-java/ |
|
|
| Flyweight | Structural | https://ankurm.com/flyweight-design-pattern-java/ |
|
|
| Proxy | Structural | https://ankurm.com/proxy-design-pattern-java/ |
|
|
| Chain of Responsibility | Behavioral | https://ankurm.com/chain-of-responsibility-design-pattern-java/ |
|
|
| Command | Behavioral | https://ankurm.com/command-design-pattern-java/ |
|
|
| Interpreter | Behavioral | https://ankurm.com/interpreter-design-pattern-java/ |
|
|
| Iterator | Behavioral | https://ankurm.com/iterator-design-pattern-java/ |
|
|
| Mediator | Behavioral | https://ankurm.com/mediator-design-pattern-java/ |
|
|
| Memento | Behavioral | https://ankurm.com/memento-design-pattern-java/ |
|
|
| Observer | Behavioral | https://ankurm.com/observer-design-pattern-java/ |
|
|
| State | Behavioral | https://ankurm.com/state-design-pattern-java/ |
|
|
| Strategy | Behavioral | https://ankurm.com/strategy-design-pattern-java/ |
|
|
| Template Method | Behavioral | https://ankurm.com/template-method-design-pattern-java/ |
|
|
| Visitor | Behavioral | https://ankurm.com/visitor-design-pattern-java/ |
|
|
|
|
## Post ↔ Code Mapping
|
|
|
|
Each article is split into multiple runnable parts. This section maps every post section to the exact file(s) in this repository, so you can jump straight from "what I just read" to "the file that implements it." Updated pattern-by-pattern as each article is verified against Java 25.
|
|
|
|
### Factory Method (`01-creational/factory-method/`)
|
|
|
|
| Post Section | File(s) |
|
|
|---|---|
|
|
| The Problem: Object Creation Leaks Into Business Logic | `NotificationService.java` (anti-pattern shown for contrast — not called by `Main`) |
|
|
| Part 1 — The Notification Interface | `Notification.java` |
|
|
| Part 2 — The Concrete Notification Classes | `EmailNotification.java`, `SmsNotification.java`, `PushNotification.java` |
|
|
| Part 3 — The NotificationSender Class | `NotificationSender.java` |
|
|
| Part 4 — The Concrete Sender Subclasses | `EmailSender.java`, `SmsSender.java`, `PushSender.java` |
|
|
| Part 5 — Running It: Client Code and Output | `Main.java` |
|
|
| Adding a New Channel (Slack) | `SlackNotification.java`, `SlackSender.java` |
|
|
|
|
Run it:
|
|
```bash
|
|
javac 01-creational/factory-method/*.java -d out/factory-method
|
|
java -cp out/factory-method factorymethod.Main
|
|
```
|
|
|
|
### Abstract Factory (`01-creational/abstract-factory/`)
|
|
|
|
| Post Section | File(s) |
|
|
|---|---|
|
|
| Part 1 — The Abstract Products: Button and TextField | `Button.java`, `TextField.java` |
|
|
| Part 2 — The Concrete Products (Light family) | `LightButton.java`, `LightTextField.java` |
|
|
| Part 2 — The Concrete Products (Dark family) | `DarkButton.java`, `DarkTextField.java` |
|
|
| Part 3 — The Abstract Factory: UIFactory Interface | `UIFactory.java` |
|
|
| Part 4 — The Concrete Factories | `LightThemeFactory.java`, `DarkThemeFactory.java` |
|
|
| Part 5 — The Client: Application | `Application.java`, `Main.java` |
|
|
|
|
Run it:
|
|
```bash
|
|
javac 01-creational/abstract-factory/*.java -d out/abstract-factory
|
|
java -cp out/abstract-factory abstractfactory.Main
|
|
# or, for the dark theme family:
|
|
java -Dapp.theme=dark -cp out/abstract-factory abstractfactory.Main
|
|
```
|
|
|
|
### Builder (`01-creational/builder/`)
|
|
|
|
| Post Section | File(s) |
|
|
|---|---|
|
|
| Part 1 — The Product: HttpRequest (Immutable) | `HttpRequest.java` |
|
|
| Part 2 — The Director: Encapsulating Common Configurations | `HttpClientConfig.java` |
|
|
| Part 3 — Using the Builder: Client Code | `Main.java` |
|
|
|
|
Note: the Lombok `@Builder` example and the JDK standard-library snippets (`HttpRequest.newBuilder()`, `StringBuilder`, `ProcessBuilder`) are illustrative only — they are not part of this repository's runnable example.
|
|
|
|
Run it:
|
|
```bash
|
|
javac 01-creational/builder/*.java -d out/builder
|
|
java -cp out/builder builder.Main
|
|
```
|
|
|
|
### Prototype (`01-creational/prototype/`)
|
|
|
|
| Post Section | File(s) |
|
|
|---|---|
|
|
| Part 1 — The Prototype Interface: Copyable | `Copyable.java` |
|
|
| Part 2 — The Nested Object: DocumentMetadata | `DocumentMetadata.java` |
|
|
| Part 3 — The Concrete Prototype: Document | `Document.java` |
|
|
| Part 4 — The Prototype Registry: DocumentRegistry | `DocumentRegistry.java` |
|
|
| Part 5 — Using the Prototype: Client Code | `Main.java` |
|
|
|
|
Note: the `ShallowVsDeepDemo` snippet (shallow vs. deep copy) and the `Cloneable`-based example are illustrative only — they are not part of this repository's runnable example.
|
|
|
|
Run it:
|
|
```bash
|
|
javac 01-creational/prototype/*.java -d out/prototype
|
|
java -cp out/prototype prototype.Main
|
|
```
|
|
|
|
### Singleton (`01-creational/singleton/`)
|
|
|
|
| Post Section | File(s) |
|
|
|---|---|
|
|
| Implementation 1 — Eager Initialization | `AppConfigEager.java` |
|
|
| Implementation 2 — Naïve Lazy Initialization | `AppConfigNaiveLazy.java` |
|
|
| Implementation 3 — Synchronized Method | `AppConfigSynchronized.java` |
|
|
| Implementation 4 — Double-Checked Locking | `AppConfigDCL.java` |
|
|
| Implementation 5 — Initialization-on-Demand Holder | `AppConfigHolder.java` |
|
|
| Implementation 6 — Enum Singleton | `AppConfigEnum.java` |
|
|
| Running All Six Implementations Together | `Main.java` |
|
|
|
|
Each implementation is renamed to its own class (e.g. `AppConfigEager`, `AppConfigHolder`) so all six can be compiled together in one package and compared directly. `Main.java` exercises all six in one run. The "Breaking via Reflection," "Breaking via Serialization," and Spring `@Component` snippets are illustrative only — they are not part of this repository's runnable example.
|
|
|
|
Run it:
|
|
```bash
|
|
javac 01-creational/singleton/*.java -d out/singleton
|
|
java -cp out/singleton singleton.Main
|
|
```
|
|
|
|
### Adapter (`02-structural/adapter/`)
|
|
|
|
| Post Section | File(s) |
|
|
|---|---|
|
|
| Step 1 — Define the Target Interface | `PaymentGateway.java` |
|
|
| Step 2 — The Adaptee (What You're Wrapping) | `StripeClient.java` |
|
|
| Step 3 — The Object Adapter | `StripePaymentAdapter.java` |
|
|
| Step 4 — The Client (Knows Nothing About Stripe) | `OrderService.java` |
|
|
| Putting It Together: The Main Demo | `Main.java` |
|
|
| Object Adapter vs Class Adapter | `StripePaymentClassAdapter.java` |
|
|
|
|
Note: the `InputStreamReader` JDK-adapter snippet is illustrative only — it is not part of this repository's runnable example.
|
|
|
|
Run it:
|
|
```bash
|
|
javac 02-structural/adapter/*.java -d out/adapter
|
|
java -cp out/adapter adapter.Main
|
|
```
|
|
|
|
### Bridge (`02-structural/bridge/`)
|
|
|
|
| Post Section | File(s) |
|
|
|---|---|
|
|
| Step 1 — The Implementor Interface | `Device.java` |
|
|
| Step 2 — Concrete Implementors (TV and Radio) | `TV.java`, `Radio.java` |
|
|
| Step 3 — The Abstraction (RemoteControl) | `RemoteControl.java` |
|
|
| Step 4 — Refined Abstraction (AdvancedRemote) | `AdvancedRemote.java` |
|
|
| Wiring It Together: Main Demo | `Main.java` |
|
|
|
|
Note: the "Class Explosion Problem — Visualised" pseudocode and the JDBC/SLF4J snippets are illustrative only — they are not part of this repository's runnable example.
|
|
|
|
Run it:
|
|
```bash
|
|
javac 02-structural/bridge/*.java -d out/bridge
|
|
java -cp out/bridge bridge.Main
|
|
```
|
|
|
|
### Composite (`02-structural/composite/`)
|
|
|
|
| Post Section | File(s) |
|
|
|---|---|
|
|
| The Problem: Treating Leaves and Containers Uniformly | illustrative only — not part of this repository's runnable example |
|
|
| Step 1 — The Component Interface | `FileSystemItem.java` |
|
|
| Step 2 — The Leaf (File) | `File.java` |
|
|
| Step 3 — The Composite (Directory) | `Directory.java` |
|
|
| Building and Using the Tree | `Main.java` |
|
|
|
|
Run it:
|
|
```bash
|
|
javac 02-structural/composite/*.java -d out/composite
|
|
java -cp out/composite composite.Main
|
|
```
|
|
|
|
### Decorator (`02-structural/decorator/`)
|
|
|
|
| Post Section | File(s) |
|
|
|---|---|
|
|
| Step 1 — Component Interface | `TextProcessor.java` |
|
|
| Step 2 — Concrete Component | `PlainTextProcessor.java` |
|
|
| Step 3 — Base Decorator | `TextDecorator.java` |
|
|
| Step 4 — Concrete Decorators | `UpperCaseDecorator.java`, `TrimDecorator.java`, `ProfanityFilterDecorator.java` |
|
|
| Stacking the Decorators — Order Matters | `Main.java` |
|
|
|
|
Note: the JDK `InputStream`/`BufferedInputStream`/`GZIPInputStream` snippet is illustrative only — it is not part of this repository's runnable example.
|
|
|
|
Run it:
|
|
```bash
|
|
javac 02-structural/decorator/*.java -d out/decorator
|
|
java -cp out/decorator decorator.Main
|
|
```
|
|
|
|
### Facade (`02-structural/facade/`)
|
|
|
|
| Post Section | File(s) |
|
|
|---|---|
|
|
| The Subsystem (Complex, But Unchanged) — VideoFile | `VideoFile.java` |
|
|
| The Subsystem (Complex, But Unchanged) — Codec interface | `Codec.java` |
|
|
| The Subsystem (Complex, But Unchanged) — Concrete Codecs | `MPEG4CompressionCodec.java`, `OggCompressionCodec.java` |
|
|
| The Subsystem (Complex, But Unchanged) — CodecFactory | `CodecFactory.java` |
|
|
| The Subsystem (Complex, But Unchanged) — BitrateReader | `BitrateReader.java` |
|
|
| The Subsystem (Complex, But Unchanged) — AudioMixer | `AudioMixer.java` |
|
|
| The Facade | `VideoConversionFacade.java` |
|
|
| Client Code: One Line | `Main.java` |
|
|
|
|
Note: the SLF4J `LoggerFactory`, JDBC `DriverManager`, and Spring `JdbcTemplate` snippets under "Facade in the JDK and Real Frameworks" are illustrative only — they are not part of this repository's runnable example.
|
|
|
|
Run it:
|
|
```bash
|
|
javac 02-structural/facade/*.java -d out/facade
|
|
java -cp out/facade facade.Main
|
|
```
|
|
|
|
### Flyweight (`02-structural/flyweight/`)
|
|
|
|
| Post Section | File(s) |
|
|
|---|---|
|
|
| Step 1 — The Flyweight (TreeType) | `TreeType.java` |
|
|
| Step 2 — The Factory (TreeFactory) | `TreeFactory.java` |
|
|
| Step 3 — The Context (Tree) | `Tree.java` |
|
|
| Putting the Forest Together | `Main.java` |
|
|
|
|
Note: the "Flyweight in the JDK: String Pool and Integer Cache" and "Measuring the Benefit" snippets are illustrative only — they are not part of this repository's runnable example.
|
|
|
|
Run it:
|
|
```bash
|
|
javac 02-structural/flyweight/*.java -d out/flyweight
|
|
java -cp out/flyweight flyweight.Main
|
|
```
|
|
|
|
### Proxy (`02-structural/proxy/`)
|
|
|
|
| Post Section | File(s) |
|
|
|---|---|
|
|
| The Subject Interface | `DatabaseConnection.java` |
|
|
| The Real Subject | `RealDatabaseConnection.java` |
|
|
| Virtual Proxy: Lazy Initialisation | `LazyConnectionProxy.java` |
|
|
| Logging Proxy: Cross-Cutting Concerns | `LoggingProxy.java` |
|
|
| Wiring It Together: Proxy Chaining | `Main.java` |
|
|
|
|
Note: the "Dynamic Proxy with java.lang.reflect.Proxy" snippet is illustrative only — it is not part of this repository's runnable example.
|
|
|
|
Run it:
|
|
```bash
|
|
javac 02-structural/proxy/*.java -d out/proxy
|
|
java -cp out/proxy proxy.Main
|
|
```
|
|
|
|
### Chain of Responsibility (`03-behavioral/chain-of-responsibility/`)
|
|
|
|
| Post Section | File(s) |
|
|
|---|---|
|
|
| The Problem: Rigid Routing Logic | illustrative only — not part of this repository's runnable example |
|
|
| Implementation: Support Ticket Escalation — base handler | `SupportHandler.java` |
|
|
| Implementation: Support Ticket Escalation — the ticket | `SupportTicket.java` |
|
|
| Each concrete handler checks only its own responsibility — Level 1 & 2 | `Level1Support.java`, `Level2Support.java` |
|
|
| Level3Support and CriticalIncidentTeam follow exactly the same shape | `Level3Support.java`, `CriticalIncidentTeam.java` |
|
|
| The chain is assembled in one place | `Main.java` |
|
|
|
|
Run it:
|
|
```bash
|
|
javac 03-behavioral/chain-of-responsibility/*.java -d out/chain
|
|
java -cp out/chain chain.Main
|
|
```
|
|
|
|
### Command (`03-behavioral/command/`)
|
|
|
|
| Post Section | File(s) |
|
|
|---|---|
|
|
| Step 1 — Command Interface | `Command.java` |
|
|
| Step 2 — The Receiver (TextEditor) | `TextEditor.java` |
|
|
| Step 3 — Concrete Commands | `InsertCommand.java`, `DeleteCommand.java` |
|
|
| Step 4 — The Invoker (CommandHistory) | `CommandHistory.java` |
|
|
| Demo | `Main.java` |
|
|
|
|
Run it:
|
|
```bash
|
|
javac 03-behavioral/command/*.java -d out/command
|
|
java -cp out/command command.Main
|
|
```
|
|
|
|
### Iterator (`03-behavioral/iterator/`)
|
|
|
|
| Post Section | File(s) |
|
|
|---|---|
|
|
| Custom Iterator Implementation — the Iterator interface | `BookIterator.java` |
|
|
| Custom Iterator Implementation — the element type | `Book.java` |
|
|
| Custom Iterator Implementation — the Aggregate (BookShelf, ForwardIterator, DecadeIterator) | `BookShelf.java` |
|
|
| Custom Iterator Implementation — wiring it together | `Main.java` |
|
|
|
|
Note: the "How Java's For-Each Loop Uses Iterator" snippet (`Iterable<Book>` example) is illustrative only — it is not part of this repository's runnable example.
|
|
|
|
Run it:
|
|
```bash
|
|
javac 03-behavioral/iterator/*.java -d out/iterator
|
|
java -cp out/iterator iterator.Main
|
|
```
|
|
|
|
## Reference
|
|
|
|
- *Design Patterns: Elements of Reusable Object-Oriented Software* — Gamma, Helm, Johnson, Vlissides
|
|
- https://refactoring.guru/design-patterns
|