Sync Factory Method, Abstract Factory, Builder, Prototype to Java 25; fix post/code mismatches
This commit is contained in:
@@ -1,24 +0,0 @@
|
||||
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 + ")}";
|
||||
}
|
||||
}
|
||||
8
01-creational/prototype/Copyable.java
Normal file
8
01-creational/prototype/Copyable.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package prototype;
|
||||
|
||||
// Our Prototype interface: any class that can clone itself implements this.
|
||||
// The return type T allows each implementing class to return its own type,
|
||||
// not the raw interface type, which makes the client code cleaner.
|
||||
public interface Copyable<T> {
|
||||
T copy();
|
||||
}
|
||||
46
01-creational/prototype/Document.java
Normal file
46
01-creational/prototype/Document.java
Normal file
@@ -0,0 +1,46 @@
|
||||
package prototype;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class Document implements Copyable<Document> {
|
||||
|
||||
private String title; // String: immutable, safe to share on copy
|
||||
private String content; // String: immutable, safe to share on copy
|
||||
private List<String> tags; // List: mutable, MUST be deep-copied
|
||||
private DocumentMetadata metadata; // Mutable object, MUST be deep-copied
|
||||
|
||||
public Document(String title, String content, List<String> tags, DocumentMetadata metadata) {
|
||||
this.title = title;
|
||||
this.content = content;
|
||||
this.tags = new ArrayList<>(tags); // defensive copy on construction
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
// Copy constructor: the preferred Prototype implementation in modern Java
|
||||
public Document(Document source) {
|
||||
this.title = source.title; // immutable: share
|
||||
this.content = source.content; // immutable: share
|
||||
this.tags = new ArrayList<>(source.tags); // mutable: new list
|
||||
this.metadata = source.metadata.copy(); // mutable: deep copy via Copyable
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document copy() {
|
||||
return new Document(this); // delegates to copy constructor
|
||||
}
|
||||
|
||||
// Getters and setters
|
||||
public String getTitle() { return title; }
|
||||
public void setTitle(String title) { this.title = title; }
|
||||
public String getContent() { return content; }
|
||||
public void setContent(String content) { this.content = content; }
|
||||
public List<String> getTags() { return Collections.unmodifiableList(tags); }
|
||||
public void addTag(String tag) { tags.add(tag); }
|
||||
public DocumentMetadata getMetadata() { return metadata; }
|
||||
|
||||
@Override public String toString() {
|
||||
return String.format("Document{title='%s', tags=%s, %s}", title, tags, metadata);
|
||||
}
|
||||
}
|
||||
39
01-creational/prototype/DocumentMetadata.java
Normal file
39
01-creational/prototype/DocumentMetadata.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package prototype;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
public class DocumentMetadata implements Copyable<DocumentMetadata> {
|
||||
|
||||
private String author;
|
||||
private LocalDate createdDate; // LocalDate is immutable — safe to share
|
||||
private String version;
|
||||
|
||||
public DocumentMetadata(String author, LocalDate createdDate, String version) {
|
||||
this.author = author;
|
||||
this.createdDate = createdDate; // safe: LocalDate is immutable
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
// Copy constructor: creates a new instance with the same values
|
||||
public DocumentMetadata(DocumentMetadata source) {
|
||||
this.author = source.author; // String: immutable, safe to share
|
||||
this.createdDate = source.createdDate; // LocalDate: immutable, safe to share
|
||||
this.version = source.version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocumentMetadata copy() {
|
||||
return new DocumentMetadata(this); // delegates to copy constructor
|
||||
}
|
||||
|
||||
public String getAuthor() { return author; }
|
||||
public LocalDate getCreatedDate(){ return createdDate; }
|
||||
public String getVersion() { return version; }
|
||||
public void setVersion(String v) { this.version = v; }
|
||||
public void setAuthor(String a) { this.author = a; }
|
||||
|
||||
@Override public String toString() {
|
||||
return String.format("Metadata{author='%s', date=%s, version='%s'}",
|
||||
author, createdDate, version);
|
||||
}
|
||||
}
|
||||
21
01-creational/prototype/DocumentRegistry.java
Normal file
21
01-creational/prototype/DocumentRegistry.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package prototype;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class DocumentRegistry {
|
||||
|
||||
private final Map<String, Document> prototypes = new HashMap<>();
|
||||
|
||||
// Register a prototype under a name
|
||||
public void register(String name, Document prototype) {
|
||||
prototypes.put(name, prototype);
|
||||
}
|
||||
|
||||
// Return a fresh copy of the named prototype
|
||||
public Document get(String name) {
|
||||
Document prototype = prototypes.get(name);
|
||||
if (prototype == null) throw new IllegalArgumentException("No prototype: " + name);
|
||||
return prototype.copy(); // always return a copy, never the prototype itself
|
||||
}
|
||||
}
|
||||
@@ -1,33 +1,47 @@
|
||||
package prototype;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.time.LocalDate;
|
||||
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"));
|
||||
// Create the original document (imagine this was loaded from a database)
|
||||
DocumentMetadata metadata = new DocumentMetadata("Alice", LocalDate.of(2025, 1, 15), "1.0");
|
||||
Document original = new Document(
|
||||
"Q1 Report",
|
||||
"Revenue increased by 12%...",
|
||||
List.of("finance", "quarterly"),
|
||||
metadata
|
||||
);
|
||||
|
||||
// Clone each shape - no need to know the concrete type
|
||||
List<Shape> copies = new ArrayList<>();
|
||||
for (Shape shape : originals) {
|
||||
copies.add(shape.clone());
|
||||
}
|
||||
System.out.println("Original: " + original);
|
||||
|
||||
// Mutate copies - originals are unaffected
|
||||
copies.get(0).setColor("green");
|
||||
copies.get(0).move(5, 5);
|
||||
copies.get(1).setColor("yellow");
|
||||
// Clone the document and apply only the differences
|
||||
Document draft = original.copy();
|
||||
draft.setTitle("Q1 Report — DRAFT");
|
||||
draft.addTag("draft");
|
||||
draft.getMetadata().setAuthor("Bob"); // only the copy's metadata changes
|
||||
draft.getMetadata().setVersion("1.0-draft");
|
||||
|
||||
System.out.println("--- Originals ---");
|
||||
originals.forEach(System.out::println);
|
||||
System.out.println("Draft: " + draft);
|
||||
System.out.println("Original: " + original); // unchanged — deep copy worked
|
||||
|
||||
System.out.println("\n--- Clones (mutated) ---");
|
||||
copies.forEach(System.out::println);
|
||||
// Verify independence
|
||||
System.out.println("\nSame object? " + (original == draft)); // false
|
||||
System.out.println("Same tags? " + (original.getTags() == draft.getTags())); // false
|
||||
System.out.println("Same meta? " + (original.getMetadata() == draft.getMetadata())); // false
|
||||
|
||||
System.out.println("\nSame instance? " + (originals.get(0) == copies.get(0)));
|
||||
// Registry demo: register a named template once, then hand out independent copies
|
||||
DocumentRegistry registry = new DocumentRegistry();
|
||||
registry.register("q-report-template", new Document(
|
||||
"Quarterly Report Template", "## Executive Summary\n...",
|
||||
List.of("quarterly", "finance"), metadata));
|
||||
|
||||
Document myReport = registry.get("q-report-template"); // a fresh, independent copy
|
||||
myReport.setTitle("Q2 2025 Report");
|
||||
myReport.addTag("q2");
|
||||
System.out.println("\nFrom registry: " + myReport);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
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 + ")}";
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
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; }
|
||||
}
|
||||
Reference in New Issue
Block a user