소스 검색

docs: update README to include prototype example

檀烈 2 달 전
부모
커밋
b0e587cfae

+ 8 - 0
README.md

@@ -7,6 +7,7 @@
 - `cn.qinys.learn.creational.factory` - 工厂模式示例(Factory Method)
 - `cn.qinys.learn.creational.builder` - 建造者模式示例(Builder)
 - `cn.qinys.learn.creational.singleton` - 单例模式示例(Singleton)
+ - `cn.qinys.learn.creational.prototype` - 原型模式示例(Prototype)
 
 快速开始
 
@@ -37,10 +38,17 @@ java -cp target\classes;target\test-classes cn.qinys.learn.creational.factory.Fa
 java -cp target\classes;target\test-classes cn.qinys.learn.creational.builder.BuilderDemo
 ```
 
+- 运行原型示例:
+
+```powershell
+java -cp target\classes;target\test-classes cn.qinys.learn.creational.prototype.PrototypeDemo
+```
+
 关于示例
 
 - `factory` 包中的示例展示了工厂方法模式:抽象 `Creator` 定义 `factoryMethod()`,由具体 `Creator` 返回不同的 `Product` 实现。
 - `builder` 包中的示例展示了建造者模式:`Director` 负责组装步骤,`Builder`/`ConcreteBuilder` 提供构建细节,最后得到 `Computer` 对象。
+ - `prototype` 包中的示例展示了原型模式:通过 `Prototype` 接口与 `ConcretePrototype` 的拷贝构造函数实现对象克隆,`PrototypeRegistry` 提供按需克隆功能并演示深拷贝行为。
 
 扩展与贡献
 

+ 81 - 0
src/main/java/cn/qinys/learn/creational/prototype/ConcretePrototype.java

@@ -0,0 +1,81 @@
+package cn.qinys.learn.creational.prototype;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * 具体原型,实现深拷贝
+ */
+public class ConcretePrototype implements Prototype {
+    private String id;
+    private String data;
+    private Map<String, String> config = new HashMap<>();
+
+    public ConcretePrototype() {
+    }
+
+    public ConcretePrototype(String id, String data) {
+        this.id = id;
+        this.data = data;
+    }
+
+    // copy constructor for deep clone
+    protected ConcretePrototype(ConcretePrototype other) {
+        this.id = other.id;
+        this.data = other.data;
+        this.config = new HashMap<>(other.config);
+    }
+
+    @Override
+    public Prototype clonePrototype() {
+        return new ConcretePrototype(this);
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getData() {
+        return data;
+    }
+
+    public void setData(String data) {
+        this.data = data;
+    }
+
+    public Map<String, String> getConfig() {
+        return config;
+    }
+
+    public void setConfig(Map<String, String> config) {
+        this.config = config;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        ConcretePrototype that = (ConcretePrototype) o;
+        return Objects.equals(id, that.id) && Objects.equals(data, that.data) && Objects.equals(config, that.config);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(id, data, config);
+    }
+
+    @Override
+    public String toString() {
+        return "ConcretePrototype{" +
+                "id='" + id + '\'' +
+                ", data='" + data + '\'' +
+                ", config=" + config +
+                '}';
+    }
+}
+

+ 12 - 0
src/main/java/cn/qinys/learn/creational/prototype/Prototype.java

@@ -0,0 +1,12 @@
+package cn.qinys.learn.creational.prototype;
+
+/**
+ * 原型接口,定义克隆方法
+ */
+public interface Prototype {
+    /**
+     * 返回当前对象的克隆(通常是深拷贝)
+     */
+    Prototype clonePrototype();
+}
+

+ 27 - 0
src/main/java/cn/qinys/learn/creational/prototype/PrototypeDemo.java

@@ -0,0 +1,27 @@
+package cn.qinys.learn.creational.prototype;
+
+/**
+ * 原型模式演示
+ */
+public class PrototypeDemo {
+    public static void main(String[] args) {
+        ConcretePrototype original = new ConcretePrototype("p1", "original-data");
+        original.getConfig().put("os", "linux");
+
+        PrototypeRegistry registry = new PrototypeRegistry();
+        registry.register("basic", original);
+
+        // 获取克隆
+        ConcretePrototype clone = (ConcretePrototype) registry.get("basic");
+
+        System.out.println("Original: " + original);
+        System.out.println("Clone:    " + clone);
+
+        // 修改克隆的配置演示深拷贝
+        clone.getConfig().put("os", "windows");
+        System.out.println("After modifying clone's config:");
+        System.out.println("Original: " + original);
+        System.out.println("Clone:    " + clone);
+    }
+}
+

+ 28 - 0
src/main/java/cn/qinys/learn/creational/prototype/PrototypeRegistry.java

@@ -0,0 +1,28 @@
+package cn.qinys.learn.creational.prototype;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 原型注册中心:保存原型实例,按需克隆
+ */
+public class PrototypeRegistry {
+    private final Map<String, Prototype> registry = new HashMap<>();
+
+    public void register(String key, Prototype prototype) {
+        registry.put(key, prototype);
+    }
+
+    public void unregister(String key) {
+        registry.remove(key);
+    }
+
+    /**
+     * 返回指定 key 对应原型的克隆(如果不存在返回 null)
+     */
+    public Prototype get(String key) {
+        Prototype p = registry.get(key);
+        return p == null ? null : p.clonePrototype();
+    }
+}
+

+ 29 - 0
src/test/java/cn/qinys/learn/creational/prototype/PrototypeTest.java

@@ -0,0 +1,29 @@
+package cn.qinys.learn.creational.prototype;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class PrototypeTest {
+
+    @Test
+    public void testCloneProducesDistinctButEqualObject() {
+        ConcretePrototype original = new ConcretePrototype("p1", "v1");
+        original.getConfig().put("k", "v");
+
+        PrototypeRegistry registry = new PrototypeRegistry();
+        registry.register("p1", original);
+
+        ConcretePrototype clone = (ConcretePrototype) registry.get("p1");
+
+        assertNotNull(clone);
+        assertNotSame(original, clone, "Clone should be a different object instance");
+        assertEquals(original, clone, "Clone should be equal in content to original");
+
+        // Modify clone's config and verify original is unchanged (deep copy)
+        clone.getConfig().put("k", "v2");
+        assertEquals("v", original.getConfig().get("k"));
+        assertEquals("v2", clone.getConfig().get("k"));
+    }
+}
+