Add creational patterns, Interpreter; remove scripts; update README

This commit is contained in:
2026-06-13 16:22:13 +00:00
parent a5beb61425
commit 2f684bf3d7
38 changed files with 435 additions and 350 deletions

View File

@@ -0,0 +1,21 @@
package abstractfactory;
/** Client - uses the factory without knowing concrete classes */
public class Application {
private final Button button;
private final Checkbox checkbox;
public Application(GUIFactory factory) {
button = factory.createButton();
checkbox = factory.createCheckbox();
}
public void render() {
button.render();
checkbox.render();
}
public void simulateClick() {
button.onClick();
}
}

View File

@@ -0,0 +1,6 @@
package abstractfactory;
public interface Button {
void render();
void onClick();
}

View File

@@ -0,0 +1,5 @@
package abstractfactory;
public interface Checkbox {
void render();
}

View File

@@ -0,0 +1,7 @@
package abstractfactory;
/** Abstract Factory - creates families of related UI components */
public interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}

View File

@@ -0,0 +1,6 @@
package abstractfactory;
public class MacButton implements Button {
@Override public void render() { System.out.println("[Mac] Rendering button with rounded corners"); }
@Override public void onClick() { System.out.println("[Mac] Button clicked - glow animation"); }
}

View File

@@ -0,0 +1,5 @@
package abstractfactory;
public class MacCheckbox implements Checkbox {
@Override public void render() { System.out.println("[Mac] Rendering checkbox with rounded tick box"); }
}

View File

@@ -0,0 +1,6 @@
package abstractfactory;
public class MacFactory implements GUIFactory {
@Override public Button createButton() { return new MacButton(); }
@Override public Checkbox createCheckbox() { return new MacCheckbox(); }
}

View File

@@ -0,0 +1,22 @@
package abstractfactory;
public class Main {
public static void main(String[] args) {
System.out.println("=== Abstract Factory Pattern Demo ===\n");
String os = System.getProperty("os.name", "Windows").toLowerCase();
GUIFactory factory = os.contains("mac") ? new MacFactory() : new WindowsFactory();
System.out.println("Detected OS family: " + (os.contains("mac") ? "Mac" : "Windows"));
System.out.println();
Application app = new Application(factory);
app.render();
app.simulateClick();
System.out.println("\n--- Forcing Mac UI ---");
Application macApp = new Application(new MacFactory());
macApp.render();
macApp.simulateClick();
}
}

View File

@@ -0,0 +1,6 @@
package abstractfactory;
public class WindowsButton implements Button {
@Override public void render() { System.out.println("[Windows] Rendering button with square corners"); }
@Override public void onClick() { System.out.println("[Windows] Button clicked - raised border effect"); }
}

View File

@@ -0,0 +1,5 @@
package abstractfactory;
public class WindowsCheckbox implements Checkbox {
@Override public void render() { System.out.println("[Windows] Rendering checkbox with square tick box"); }
}

View File

@@ -0,0 +1,6 @@
package abstractfactory;
public class WindowsFactory implements GUIFactory {
@Override public Button createButton() { return new WindowsButton(); }
@Override public Checkbox createCheckbox() { return new WindowsCheckbox(); }
}

View File

@@ -0,0 +1,12 @@
package builder;
/** Director knows how to build common configurations */
public class Director {
public House buildStarter(House.Builder builder) {
return builder.rooms(2).floors(1).garage(false).roofType("gabled").build();
}
public House buildLuxury(House.Builder builder) {
return builder.rooms(6).floors(3).garage(true).garden(true).pool(true).roofType("hip").build();
}
}

View File

@@ -0,0 +1,43 @@
package builder;
public class House {
private final int rooms;
private final int floors;
private final boolean hasGarage;
private final boolean hasGarden;
private final boolean hasPool;
private final String roofType;
private House(Builder builder) {
this.rooms = builder.rooms;
this.floors = builder.floors;
this.hasGarage = builder.hasGarage;
this.hasGarden = builder.hasGarden;
this.hasPool = builder.hasPool;
this.roofType = builder.roofType;
}
@Override
public String toString() {
return "House{rooms=" + rooms + ", floors=" + floors
+ ", garage=" + hasGarage + ", garden=" + hasGarden
+ ", pool=" + hasPool + ", roof='" + roofType + "'}";
}
public static class Builder {
private int rooms = 1;
private int floors = 1;
private boolean hasGarage = false;
private boolean hasGarden = false;
private boolean hasPool = false;
private String roofType = "flat";
public Builder rooms(int rooms) { this.rooms = rooms; return this; }
public Builder floors(int floors) { this.floors = floors; return this; }
public Builder garage(boolean v) { this.hasGarage = v; return this; }
public Builder garden(boolean v) { this.hasGarden = v; return this; }
public Builder pool(boolean v) { this.hasPool = v; return this; }
public Builder roofType(String roofType) { this.roofType = roofType; return this; }
public House build() { return new House(this); }
}
}

View File

@@ -0,0 +1,20 @@
package builder;
public class Main {
public static void main(String[] args) {
System.out.println("=== Builder Pattern Demo ===\n");
Director director = new Director();
House starter = director.buildStarter(new House.Builder());
System.out.println("Starter home : " + starter);
House luxury = director.buildLuxury(new House.Builder());
System.out.println("Luxury home : " + luxury);
// Client builds a custom house directly without the Director
House custom = new House.Builder()
.rooms(4).floors(2).garden(true).roofType("mansard").build();
System.out.println("Custom home : " + custom);
}
}

View File

@@ -0,0 +1,11 @@
package factorymethod;
public class EmailNotification implements Notification {
private final String email;
public EmailNotification(String email) { this.email = email; }
@Override
public void send(String message) {
System.out.println("Email -> " + email + ": " + message);
}
}

View File

@@ -0,0 +1,11 @@
package factorymethod;
public class EmailService extends NotificationService {
private final String email;
public EmailService(String email) { this.email = email; }
@Override
protected Notification createNotification() {
return new EmailNotification(email);
}
}

View File

@@ -0,0 +1,17 @@
package factorymethod;
public class Main {
public static void main(String[] args) {
System.out.println("=== Factory Method Pattern Demo ===\n");
NotificationService[] services = {
new EmailService("alice@example.com"),
new SmsService("+1-555-0123"),
new PushService("device-token-abc123")
};
for (NotificationService service : services) {
service.notifyUser("Your order #1042 has been shipped!");
}
}
}

View File

@@ -0,0 +1,5 @@
package factorymethod;
public interface Notification {
void send(String message);
}

View File

@@ -0,0 +1,11 @@
package factorymethod;
/** Creator - declares the factory method */
public abstract class NotificationService {
protected abstract Notification createNotification();
public void notifyUser(String message) {
Notification n = createNotification();
n.send(message);
}
}

View File

@@ -0,0 +1,11 @@
package factorymethod;
public class PushNotification implements Notification {
private final String deviceToken;
public PushNotification(String deviceToken) { this.deviceToken = deviceToken; }
@Override
public void send(String message) {
System.out.println("Push -> " + deviceToken + ": " + message);
}
}

View File

@@ -0,0 +1,11 @@
package factorymethod;
public class PushService extends NotificationService {
private final String token;
public PushService(String token) { this.token = token; }
@Override
protected Notification createNotification() {
return new PushNotification(token);
}
}

View File

@@ -0,0 +1,11 @@
package factorymethod;
public class SmsNotification implements Notification {
private final String phone;
public SmsNotification(String phone) { this.phone = phone; }
@Override
public void send(String message) {
System.out.println("SMS -> " + phone + ": " + message);
}
}

View File

@@ -0,0 +1,11 @@
package factorymethod;
public class SmsService extends NotificationService {
private final String phone;
public SmsService(String phone) { this.phone = phone; }
@Override
protected Notification createNotification() {
return new SmsNotification(phone);
}
}

View File

@@ -0,0 +1,24 @@
package prototype;
public class Circle extends Shape {
private int radius;
public Circle(int radius, String color) {
this.radius = radius;
this.color = color;
}
/** Copy constructor used by clone() */
private Circle(Circle source) {
super(source);
this.radius = source.radius;
}
@Override
public Circle clone() { return new Circle(this); }
@Override
public String toString() {
return "Circle{color=" + color + ", radius=" + radius + ", pos=(" + x + "," + y + ")}";
}
}

View File

@@ -0,0 +1,33 @@
package prototype;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
System.out.println("=== Prototype Pattern Demo ===\n");
List<Shape> originals = new ArrayList<>();
originals.add(new Circle(10, "red"));
originals.add(new Rectangle(20, 30, "blue"));
// Clone each shape - no need to know the concrete type
List<Shape> copies = new ArrayList<>();
for (Shape shape : originals) {
copies.add(shape.clone());
}
// Mutate copies - originals are unaffected
copies.get(0).setColor("green");
copies.get(0).move(5, 5);
copies.get(1).setColor("yellow");
System.out.println("--- Originals ---");
originals.forEach(System.out::println);
System.out.println("\n--- Clones (mutated) ---");
copies.forEach(System.out::println);
System.out.println("\nSame instance? " + (originals.get(0) == copies.get(0)));
}
}

View File

@@ -0,0 +1,26 @@
package prototype;
public class Rectangle extends Shape {
private int width;
private int height;
public Rectangle(int width, int height, String color) {
this.width = width;
this.height = height;
this.color = color;
}
private Rectangle(Rectangle source) {
super(source);
this.width = source.width;
this.height = source.height;
}
@Override
public Rectangle clone() { return new Rectangle(this); }
@Override
public String toString() {
return "Rectangle{color=" + color + ", size=" + width + "x" + height + ", pos=(" + x + "," + y + ")}";
}
}

View File

@@ -0,0 +1,22 @@
package prototype;
/** Prototype - every shape can clone itself */
public abstract class Shape {
protected String color;
protected int x;
protected int y;
protected Shape(Shape source) {
this.color = source.color;
this.x = source.x;
this.y = source.y;
}
protected Shape() {}
public abstract Shape clone();
public void setColor(String color) { this.color = color; }
public String getColor() { return color; }
public void move(int x, int y) { this.x = x; this.y = y; }
}

View File

@@ -0,0 +1,34 @@
package singleton;
/**
* Thread-safe Singleton using double-checked locking.
*/
public class DatabaseConnection {
private static volatile DatabaseConnection instance;
private final String url;
private int queryCount = 0;
private DatabaseConnection() {
this.url = "jdbc:mysql://localhost:3306/myapp";
System.out.println("Establishing connection to " + url);
}
public static DatabaseConnection getInstance() {
if (instance == null) {
synchronized (DatabaseConnection.class) {
if (instance == null) {
instance = new DatabaseConnection();
}
}
}
return instance;
}
public String executeQuery(String sql) {
queryCount++;
return "Result #" + queryCount + " for: " + sql;
}
public int getQueryCount() { return queryCount; }
public String getUrl() { return url; }
}

View File

@@ -0,0 +1,19 @@
package singleton;
public class Main {
public static void main(String[] args) {
System.out.println("=== Singleton Pattern Demo ===\n");
DatabaseConnection c1 = DatabaseConnection.getInstance();
DatabaseConnection c2 = DatabaseConnection.getInstance();
DatabaseConnection c3 = DatabaseConnection.getInstance();
System.out.println("\nAll three references same instance? " + (c1 == c2 && c2 == c3));
System.out.println(c1.executeQuery("SELECT * FROM users"));
System.out.println(c2.executeQuery("SELECT * FROM orders"));
System.out.println(c3.executeQuery("SELECT COUNT(*) FROM products"));
System.out.println("\nTotal queries: " + c1.getQueryCount());
}
}