Add all 23 GoF design pattern implementations

This commit is contained in:
2026-07-25 10:50:29 +05:30
commit f5688a6b32
164 changed files with 4371 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
package factorymethod;
public class EmailNotification implements Notification {
@Override
public void send(String recipient, String message) {
// In production: use JavaMail or Spring Mail
System.out.printf(" [EMAIL] To: %s | Body: %s%n", recipient, message);
}
@Override
public String getType() { return "EMAIL"; }
}

View File

@@ -0,0 +1,8 @@
package factorymethod;
public class EmailSender extends NotificationSender {
@Override
protected Notification createNotification() {
return new EmailNotification();
}
}

View File

@@ -0,0 +1,23 @@
package factorymethod;
public class Main {
public static void main(String[] args) {
// The client only knows about NotificationSender (the Creator)
NotificationSender sender;
sender = new EmailSender();
sender.notify("alice@example.com", "Your order has shipped!");
sender = new SmsSender();
sender.notify("+1-555-0100", "OTP: 482910");
sender = new PushSender();
sender.notify("device-token-xyz", "New message from Bob");
// Adding Slack: just swap the creator. Client code doesn't change.
sender = new SlackSender(); // new class, nothing else touched
sender.notify("#alerts", "CPU usage above 90%");
}
}

View File

@@ -0,0 +1,11 @@
package factorymethod;
public interface Notification {
// Every notification must know how to deliver itself
void send(String recipient, String message);
// Used by the Creator for logging — it needs to know the type
// without knowing the concrete class
String getType();
}

View File

@@ -0,0 +1,31 @@
package factorymethod;
public abstract class NotificationSender {
// THE factory method — this is the one thing subclasses override.
// It returns a Notification (the Product interface), never a concrete class.
protected abstract Notification createNotification();
// The shared workflow — marked final so subclasses cannot change it.
// It calls createNotification() to get the right notification,
// then runs the same steps every time regardless of which channel was created.
public final void notify(String recipient, String message) {
Notification notification = createNotification(); // delegate creation
System.out.println("Sending " + notification.getType() + " notification...");
notification.send(recipient, message); // use the Product interface
System.out.println("Delivered.");
}
// Shared retry logic — works for all channels without change
public void notifyWithRetry(String recipient, String message, int maxRetries) {
for (int attempt = 1; attempt <= maxRetries; attempt++) {
try {
notify(recipient, message);
return; // success — exit
} catch (Exception e) {
System.err.printf("Attempt %d failed: %s%n", attempt, e.getMessage());
}
}
throw new RuntimeException("All " + maxRetries + " attempts failed");
}
}

View File

@@ -0,0 +1,24 @@
package factorymethod;
public class NotificationService {
public void send(String type, String recipient, String message) {
// Creation logic mixed with business logic
Notification notification;
if ("EMAIL".equals(type)) {
notification = new EmailNotification();
} else if ("SMS".equals(type)) {
notification = new SmsNotification();
} else if ("PUSH".equals(type)) {
notification = new PushNotification();
} else {
throw new IllegalArgumentException("Unknown type: " + type);
}
// Business logic that should never change
System.out.println("Sending " + type + " to " + recipient);
notification.send(recipient, message);
System.out.println("Delivered.");
}
}

View File

@@ -0,0 +1,13 @@
package factorymethod;
public class PushNotification implements Notification {
@Override
public void send(String recipient, String message) {
// In production: use Firebase FCM
System.out.printf(" [PUSH] To: %s | Alert: %s%n", recipient, message);
}
@Override
public String getType() { return "PUSH"; }
}

View File

@@ -0,0 +1,8 @@
package factorymethod;
public class PushSender extends NotificationSender {
@Override
protected Notification createNotification() {
return new PushNotification();
}
}

View File

@@ -0,0 +1,32 @@
# Factory Method Design Pattern — Java Example
**Pattern:** Creational → Factory Method
**Article:** https://ankurm.com/factory-method-design-pattern-java/
## What this example shows
A notification system where the "send" logic decides which channel object to create, instead of the client doing it with a switch statement. `Notification` is the product interface; `EmailNotification`, `SmsNotification`, and `PushNotification` are concrete products. `NotificationSender` declares the factory method and a template `send()` step shared by every channel; `EmailSender`, `SmsSender`, and `PushSender` each override the factory method to produce their own notification type. `NotificationService` is shown separately as the anti-pattern this pattern replaces — it is not called by `Main`. `Main` demonstrates the cost of adding a new channel (Slack) by adding one new product and one new creator, with zero changes to existing classes.
## How to run
```bash
javac factory-method/*.java -d out/factory-method
java -cp out/factory-method factorymethod.Main
```
Requires Java 25.
## Post Section ↔ File Mapping
| 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` |
Article: https://ankurm.com/factory-method-design-pattern-java/
All patterns: https://ankurm.com/design-patterns-java/

View File

@@ -0,0 +1,11 @@
package factorymethod;
// New Concrete Product — knows how to send to Slack
public class SlackNotification implements Notification {
@Override
public void send(String recipient, String message) {
System.out.printf(" [SLACK] Channel: %s | Message: %s%n", recipient, message);
}
@Override
public String getType() { return "SLACK"; }
}

View File

@@ -0,0 +1,9 @@
package factorymethod;
// New Concrete Creator — knows to create a SlackNotification
public class SlackSender extends NotificationSender {
@Override
protected Notification createNotification() {
return new SlackNotification();
}
}

View File

@@ -0,0 +1,13 @@
package factorymethod;
public class SmsNotification implements Notification {
@Override
public void send(String recipient, String message) {
// In production: use Twilio SDK
System.out.printf(" [SMS] To: %s | Text: %s%n", recipient, message);
}
@Override
public String getType() { return "SMS"; }
}

View File

@@ -0,0 +1,8 @@
package factorymethod;
public class SmsSender extends NotificationSender {
@Override
protected Notification createNotification() {
return new SmsNotification();
}
}