创建型-原型模式

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类负责存储和提供原型对象的克隆
  • 深拷贝与浅拷贝:
    • 浅拷贝:基本类型字段被复制,引用类型字段共享同一对象
    • 深拷贝:所有字段都被复制,包括引用类型字段
  • 适用场景
    • 当创建对象的成本较高时(如数据库查询、复杂计算)
    • 当需要创建大量相似对象时
    • 当需要避免使用类的构造函数时
    • 当系统需要独立于产品的创建、构成和表示时
相关推荐
想吃火锅100514 天前
【前端手撕】instanceof
前端·javascript·原型模式
UXbot14 天前
帮助企业低门槛开展AI应用开发的平台推荐
前端·低代码·ui·交互·产品经理·原型模式·web app
UXbot15 天前
如何选择适合公司项目的UI设计工具?企业选型指南
前端·低代码·ui·团队开发·原型模式·设计规范·web app
UXbot15 天前
原型设计工具如何帮助新人快速进入产品行业?
前端·低代码·ui·交互·团队开发·原型模式·web app
sunny.day19 天前
js原型与原型链
开发语言·javascript·原型模式·js原型链
UXbot20 天前
AI网页开发工具能替代工具吗?5大平台对比
前端·人工智能·低代码·ui·原型模式·web app
weixin_3077791320 天前
从“大海捞针”到“主动推理”:AI如何重塑云原生故障诊断的根因链
开发语言·人工智能·算法·自动化·原型模式
swordbob20 天前
prototype 注入到 singleton 里,prototype是否还是线程安全的
安全·spring·单例模式·原型模式
isNotNullX21 天前
企业数据中台建设,ETL工具选错了会踩哪些坑?
数据仓库·etl·原型模式
半个烧饼不加肉21 天前
JS 底层探究-- 普通函数和构造函数
开发语言·javascript·原型模式