创建型-原型模式

1. 项目结构

bash 复制代码
	prototype-pattern-demo/
	├── pom.xml
	├── src/
	│   ├── main/
	│   │   └── java/
	│   │       └── com/
	│   │           └── example/
	│   │               └── prototype/
	│   │                   ├── Main.java
	│   │                   ├── Shape.java
	│   │                   ├── Circle.java
	│   │                   ├── Rectangle.java
	│   │                   ├── ShapeCache.java
	│   │                   └── ShapeType.java
	│   └── test/
	│       └── java/
	│           └── com/
	│               └── example/
	│                   └── prototype/
	│                       └── PrototypePatternTest.java

1. Maven配置文件 (pom.xml)

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
	<project xmlns="http://maven.apache.org/POM/4.0.0"
	         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
	         http://maven.apache.org/xsd/maven-4.0.0.xsd">
	    <modelVersion>4.0.0</modelVersion>
	
	    <groupId>com.example</groupId>
	    <artifactId>prototype-pattern-demo</artifactId>
	    <version>1.0-SNAPSHOT</version>
	    <packaging>jar</packaging>
	    
	    <properties>
	        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	        <maven.compiler.source>1.8</maven.compiler.source>
	        <maven.compiler.target>1.8</maven.compiler.target>
	        <java.version>1.8</java.version>
	        <junit.version>4.13.2</junit.version>
	    </properties>
	
	    <dependencies>
	        <dependency>
	            <groupId>junit</groupId>
	            <artifactId>junit</artifactId>
	            <version>${junit.version}</version>
	            <scope>test</scope>
	        </dependency>
	    </dependencies>
	
	    <build>
	        <plugins>
	            <plugin>
	                <groupId>org.apache.maven.plugins</groupId>
	                <artifactId>maven-compiler-plugin</artifactId>
	                <version>3.8.1</version>
	                <configuration>
	                    <source>${java.version}</source>
	                    <target>${java.version}</target>
	                </configuration>
	            </plugin>
	        </plugins>
	    </build>
	</project>

2. 代码实现

1. Shape.java (原型接口)

java 复制代码
package com.example.prototype;
	
	/**
	 * 形状接口,作为原型模式的基础接口
	 * 实现了Cloneable接口,支持克隆功能
	 */
	public abstract class Shape implements Cloneable {
	    
	    private String id;
	    private String type;
	    
	    public Shape() {
	        // 默认构造函数
	    }
	    
	    public Shape(String id, String type) {
	        this.id = id;
	        this.type = type;
	    }
	    
	    /**
	     * 抽象方法 - 绘制形状
	     */
	    public abstract void draw();
	    
	    /**
	     * 获取ID
	     */
	    public String getId() {
	        return id;
	    }
	    
	    /**
	     * 设置ID
	     */
	    public void setId(String id) {
	        this.id = id;
	    }
	    
	    /**
	     * 获取类型
	     */
	    public String getType() {
	        return type;
	    }
	    
	    /**
	     * 设置类型
	     */
	    public void setType(String type) {
	        this.type = type;
	    }
	    
	    /**
	     * 重写clone方法,实现浅拷贝
	     * 注意:如果对象中有引用类型的字段,需要实现深拷贝
	     */
	    @Override
	    public Object clone() {
	        Object clone = null;
	        try {
	            clone = super.clone();
	        } catch (CloneNotSupportedException e) {
	            e.printStackTrace();
	        }
	        return clone;
	    }
	    
	    /**
	     * 深拷贝方法示例
	     * 可以根据需要实现深拷贝逻辑
	     */
	    public Shape deepClone() {
	        Shape shape = null;
	        try {
	            // 浅拷贝基础字段
	            shape = (Shape) super.clone();
	            // 这里可以添加对引用类型字段的深拷贝逻辑
	            // 例如:shape.someReferenceField = this.someReferenceField.clone();
	        } catch (CloneNotSupportedException e) {
	            e.printStackTrace();
	        }
	        return shape;
	    }
	    
	    @Override
	    public String toString() {
	        return "Shape [id=" + id + ", type=" + type + "]";
	    }
	}

2. Circle.java (具体原型类)

java 复制代码
package com.example.prototype;

/**
 * 圆形类 - 具体原型实现
 */
public class Circle extends Shape {
    
    private double radius;
    private String color;
    
    // 用于演示深拷贝需要的引用类型字段
    private CircleProperties properties;
    
    public Circle() {
        super();
        setType("Circle");
    }
    
    public Circle(String id, double radius, String color) {
        super(id, "Circle");
        this.radius = radius;
        this.color = color;
        this.properties = new CircleProperties("Standard", 1.0);
    }
    
    @Override
    public void draw() {
        System.out.println("Drawing a Circle with ID: " + getId() + 
                          ", Radius: " + radius + 
                          ", Color: " + color +
                          ", Properties: " + (properties != null ? properties.getName() : "N/A"));
    }
    
    public double getRadius() {
        return radius;
    }
    
    public void setRadius(double radius) {
        this.radius = radius;
    }
    
    public String getColor() {
        return color;
    }
    
    public void setColor(String color) {
        this.color = color;
    }
    
    public CircleProperties getProperties() {
        return properties;
    }
    
    public void setProperties(CircleProperties properties) {
        this.properties = properties;
    }
    
    /**
     * 重写clone方法,实现深拷贝
     */
    @Override
    public Object clone() {
        Circle circle = (Circle) super.clone();
        
        // 深拷贝引用类型字段
        if (this.properties != null) {
            circle.properties = (CircleProperties) this.properties.clone();
        }
        
        return circle;
    }
    
    /**
     * 圆形属性内部类,用于演示深拷贝
     */
    public static class CircleProperties implements Cloneable {
        private String name;
        private double thickness;
        
        public CircleProperties(String name, double thickness) {
            this.name = name;
            this.thickness = thickness;
        }
        
        public String getName() {
            return name;
        }
        
        public void setName(String name) {
            this.name = name;
        }
        
        public double getThickness() {
            return thickness;
        }
        
        public void setThickness(double thickness) {
            this.thickness = thickness;
        }
        
        @Override
        public Object clone() {
            try {
                return super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
                return null;
            }
        }
        
        @Override
        public String toString() {
            return "CircleProperties [name=" + name + ", thickness=" + thickness + "]";
        }
    }
    
    @Override
    public String toString() {
        return "Circle [id=" + getId() + 
               ", type=" + getType() + 
               ", radius=" + radius + 
               ", color=" + color + 
               ", properties=" + properties + "]";
    }
}

3. Rectangle.java (具体原型类)

java 复制代码
package com.example.prototype;

/**
 * 矩形类 - 具体原型实现
 */
public class Rectangle extends Shape {
    
    private double width;
    private double height;
    private boolean filled;
    
    public Rectangle() {
        super();
        setType("Rectangle");
    }
    
    public Rectangle(String id, double width, double height, boolean filled) {
        super(id, "Rectangle");
        this.width = width;
        this.height = height;
        this.filled = filled;
    }
    
    @Override
    public void draw() {
        System.out.println("Drawing a Rectangle with ID: " + getId() + 
                          ", Width: " + width + 
                          ", Height: " + height + 
                          ", Filled: " + filled);
    }
    
    public double getWidth() {
        return width;
    }
    
    public void setWidth(double width) {
        this.width = width;
    }
    
    public double getHeight() {
        return height;
    }
    
    public void setHeight(double height) {
        this.height = height;
    }
    
    public boolean isFilled() {
        return filled;
    }
    
    public void setFilled(boolean filled) {
        this.filled = filled;
    }
    
    @Override
    public Object clone() {
        return super.clone();
    }
    
    @Override
    public String toString() {
        return "Rectangle [id=" + getId() + 
               ", type=" + getType() + 
               ", width=" + width + 
               ", height=" + height + 
               ", filled=" + filled + "]";
    }
}

4. ShapeType.java (形状类型枚举)

java 复制代码
package com.example.prototype;

/**
 * 形状类型枚举
 */
public enum ShapeType {
    CIRCLE("CIRCLE"),
    RECTANGLE("RECTANGLE");
    
    private final String type;
    
    ShapeType(String type) {
        this.type = type;
    }
    
    public String getType() {
        return type;
    }
}

5. ShapeCache.java (原型管理器/注册表)

java 复制代码
package com.example.prototype;

import java.util.HashMap;
import java.util.Map;

/**
 * 形状缓存类 - 原型管理器
 * 用于创建和存储原型对象,并在需要时提供它们的克隆
 */
public class ShapeCache {
    
    private static Map<String, Shape> shapeMap = new HashMap<>();
    
    /**
     * 加载缓存,初始化原型对象
     */
    public static void loadCache() {
        // 创建圆形原型
        Circle circle = new Circle("1", 10.0, "Red");
        circle.setProperties(new Circle.CircleProperties("Bold", 2.0));
        shapeMap.put(ShapeType.CIRCLE.getType(), circle);
        
        // 创建矩形原型
        Rectangle rectangle = new Rectangle("2", 20.0, 30.0, true);
        shapeMap.put(ShapeType.RECTANGLE.getType(), rectangle);
    }
    
    /**
     * 根据类型获取形状的克隆
     */
    public static Shape getShape(String type) {
        Shape cachedShape = shapeMap.get(type);
        if (cachedShape == null) {
            throw new IllegalArgumentException("Unknown shape type: " + type);
        }
        return (Shape) cachedShape.clone();
    }
    
    /**
     * 获取原始原型(非克隆)
     * 用于演示目的
     */
    public static Shape getOriginalShape(String type) {
        return shapeMap.get(type);
    }
    
    /**
     * 添加新的原型到缓存
     */
    public static void addShape(String key, Shape shape) {
        shapeMap.put(key, shape);
    }
    
    /**
     * 清除缓存
     */
    public static void clearCache() {
        shapeMap.clear();
    }
    
    /**
     * 获取缓存大小
     */
    public static int getCacheSize() {
        return shapeMap.size();
    }
}

6. Main.java

java 复制代码
package com.example.prototype;

/**
 * 原型模式演示主类
 */
public class Main {
    
    public static void main(String[] args) {
        System.out.println("=== 原型模式演示 ===");
        
        // 1. 加载原型到缓存
        ShapeCache.loadCache();
        System.out.println("已加载 " + ShapeCache.getCacheSize() + " 个原型到缓存");
        
        // 2. 演示浅拷贝和深拷贝
        demonstrateShallowAndDeepCopy();
        
        // 3. 使用原型缓存创建对象
        System.out.println("\n--- 使用原型缓存创建对象 ---");
        
        // 克隆圆形
        Shape clonedCircle = ShapeCache.getShape(ShapeType.CIRCLE.getType());
        clonedCircle.setId("100"); // 修改ID以区分原型
        System.out.println("克隆的圆形: " + clonedCircle);
        clonedCircle.draw();
        
        // 克隆矩形
        Shape clonedRectangle = ShapeCache.getShape(ShapeType.RECTANGLE.getType());
        clonedRectangle.setId("200"); // 修改ID以区分原型
        System.out.println("\n克隆的矩形: " + clonedRectangle);
        clonedRectangle.draw();
        
        // 4. 演示原型模式的优势 - 高效创建复杂对象
        System.out.println("\n--- 原型模式的优势演示 ---");
        demonstratePrototypeAdvantage();
        
        // 5. 演示动态添加原型
        System.out.println("\n--- 动态添加原型演示 ---");
        demonstrateDynamicPrototype();
    }
    
    /**
     * 演示浅拷贝和深拷贝的区别
     */
    private static void demonstrateShallowAndDeepCopy() {
        System.out.println("\n--- 浅拷贝 vs 深拷贝演示 ---");
        
        // 获取原始圆形原型
        Circle originalCircle = (Circle) ShapeCache.getOriginalShape(ShapeType.CIRCLE.getType());
        System.out.println("原始圆形: " + originalCircle);
        
        // 使用clone方法(已实现深拷贝)
        Circle clonedCircle = (Circle) originalCircle.clone();
        clonedCircle.setId("3");
        clonedCircle.setColor("Blue");
        
        // 修改克隆对象的引用类型字段
        if (clonedCircle.getProperties() != null) {
            clonedCircle.getProperties().setName("Thin");
        }
        
        System.out.println("克隆后修改的圆形: " + clonedCircle);
        System.out.println("原始圆形(查看是否受影响): " + originalCircle);
        
        // 验证深拷贝:原始对象的引用类型字段不应被修改
        if (!originalCircle.getProperties().getName().equals(clonedCircle.getProperties().getName())) {
            System.out.println("✓ 深拷贝成功:修改克隆对象的属性不影响原始对象");
        }
    }
    
    /**
     * 演示原型模式在创建复杂对象时的优势
     */
    private static void demonstratePrototypeAdvantage() {
        System.out.println("创建1000个复杂圆形对象:");
        
        long startTime, endTime;
        
        // 传统方式创建
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000; i++) {
            Circle circle = new Circle(String.valueOf(i), 10.0, "Red");
            circle.setProperties(new Circle.CircleProperties("Standard", 1.0));
            // 模拟复杂初始化
            try {
                Thread.sleep(0, 100); // 微小延迟模拟复杂初始化
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        endTime = System.currentTimeMillis();
        System.out.println("传统方式耗时: " + (endTime - startTime) + "ms");
        
        // 原型模式创建
        startTime = System.currentTimeMillis();
        Circle prototype = new Circle("prototype", 10.0, "Red");
        prototype.setProperties(new Circle.CircleProperties("Standard", 1.0));
        
        for (int i = 0; i < 1000; i++) {
            Circle cloned = (Circle) prototype.clone();
            cloned.setId(String.valueOf(i + 1000));
        }
        endTime = System.currentTimeMillis();
        System.out.println("原型模式耗时: " + (endTime - startTime) + "ms");
        
        System.out.println("✓ 原型模式在创建大量相似对象时更高效");
    }
    
    /**
     * 演示动态添加原型
     */
    private static void demonstrateDynamicPrototype() {
        // 创建新的原型
        Rectangle newRectangle = new Rectangle("dynamic-1", 50.0, 60.0, false);
        
        // 动态添加到缓存
        ShapeCache.addShape("NEW_RECTANGLE", newRectangle);
        
        // 使用新原型创建对象
        Shape clonedNewRect = ShapeCache.getShape("NEW_RECTANGLE");
        clonedNewRect.setId("dynamic-2");
        System.out.println("动态添加的原型创建的矩形: " + clonedNewRect);
        clonedNewRect.draw();
        
        System.out.println("当前缓存大小: " + ShapeCache.getCacheSize());
    }
}

7. PrototypePatternTest.java

java 复制代码
package com.example.prototype;

import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;

/**
 * 原型模式测试类
 */
public class PrototypePatternTest {
    
    @Before
    public void setUp() {
        // 每次测试前清空并重新加载缓存
        ShapeCache.clearCache();
        ShapeCache.loadCache();
    }
    
    @Test
    public void testShapeCloning() {
        // 测试圆形克隆
        Shape circle1 = ShapeCache.getShape(ShapeType.CIRCLE.getType());
        circle1.setId("test-circle-1");
        
        Shape circle2 = ShapeCache.getShape(ShapeType.CIRCLE.getType());
        circle2.setId("test-circle-2");
        
        // 验证两个对象是不同的实例
        assertNotSame("克隆对象应该是不同的实例", circle1, circle2);
        
        // 验证类型相同
        assertEquals("克隆对象类型应该相同", circle1.getType(), circle2.getType());
        
        // 验证ID不同
        assertNotEquals("克隆对象ID应该不同", circle1.getId(), circle2.getId());
    }
    
    @Test
    public void testDeepCopy() {
        // 获取原始圆形
        Circle original = (Circle) ShapeCache.getOriginalShape(ShapeType.CIRCLE.getType());
        String originalPropertiesName = original.getProperties().getName();
        
        // 克隆并修改
        Circle cloned = (Circle) original.clone();
        cloned.getProperties().setName("Modified");
        
        // 验证原始对象未受影响
        assertEquals("原始对象的属性不应被修改", 
                    originalPropertiesName, 
                    original.getProperties().getName());
        
        assertNotEquals("克隆对象的属性应该被修改", 
                       originalPropertiesName, 
                       cloned.getProperties().getName());
    }
    
    @Test
    public void testShapeCache() {
        // 验证缓存加载
        assertEquals("缓存应该包含2个原型", 2, ShapeCache.getCacheSize());
        
        // 验证可以获取原型
        Shape circle = ShapeCache.getShape(ShapeType.CIRCLE.getType());
        assertNotNull("应该能获取圆形原型", circle);
        assertEquals("原型类型应该是Circle", "Circle", circle.getType());
        
        Shape rectangle = ShapeCache.getShape(ShapeType.RECTANGLE.getType());
        assertNotNull("应该能获取矩形原型", rectangle);
        assertEquals("原型类型应该是Rectangle", "Rectangle", rectangle.getType());
    }
    
    @Test(expected = IllegalArgumentException.class)
    public void testUnknownShapeType() {
        // 应该抛出异常
        ShapeCache.getShape("UNKNOWN_TYPE");
    }
    
    @Test
    public void testDynamicPrototypeAddition() {
        // 动态添加新原型
        Circle newCircle = new Circle("new-circle", 15.0, "Green");
        ShapeCache.addShape("NEW_CIRCLE", newCircle);
        
        // 验证缓存大小增加
        assertEquals("缓存大小应该为3", 3, ShapeCache.getCacheSize());
        
        // 验证可以获取新原型
        Shape cloned = ShapeCache.getShape("NEW_CIRCLE");
        assertNotNull("应该能获取新添加的原型", cloned);
        assertEquals("新原型的ID应该不同", "new-circle", cloned.getId());
    }
}

3. 构建和运行

  1. 使用Maven编译项目:

    bash 复制代码
    mvn clean compile
  2. 运行主程序:

    bash 复制代码
    mvn exec:java -Dexec.mainClass="com.example.prototype.Main"
  3. 运行测试:

    bash 复制代码
    mvn test
  4. 打包项目:

    bash 复制代码
    mvn package

4. 核心概念

  • 原型接口:Shape抽象类实现了Cloneable接口
  • 具体原型:Circle和Rectangle类实现具体的克隆逻辑
  • 原型管理器:ShapeCache类负责存储和提供原型对象的克隆
  • 深拷贝与浅拷贝:
    • 浅拷贝:基本类型字段被复制,引用类型字段共享同一对象
    • 深拷贝:所有字段都被复制,包括引用类型字段
  • 适用场景
    • 当创建对象的成本较高时(如数据库查询、复杂计算)
    • 当需要创建大量相似对象时
    • 当需要避免使用类的构造函数时
    • 当系统需要独立于产品的创建、构成和表示时
相关推荐
.格子衫.2 天前
JS原型链总结
开发语言·javascript·原型模式
冷崖2 天前
原型模式-创建型
设计模式·原型模式
老朱佩琪!3 天前
Unity原型模式
开发语言·经验分享·unity·设计模式·原型模式
zhougl9965 天前
区分__proto__和prototype
开发语言·javascript·原型模式
询问QQ:1808095112 天前
永磁同步电机参数辨识那些事儿
原型模式
小白勇闯网安圈12 天前
wife_wife、题目名称-文件包含、FlatScience
javascript·python·网络安全·web·原型模式
还是大剑师兰特13 天前
ES6 class相关内容详解
es6·原型模式·大剑师
ZouZou老师13 天前
C++设计模式之原型模式:以家具生产为例
c++·设计模式·原型模式
San30.14 天前
从原型链到“圣杯模式”:JavaScript 继承方案的演进与终极解法
开发语言·javascript·原型模式