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. 构建和运行
-
使用Maven编译项目:
bashmvn clean compile -
运行主程序:
bashmvn exec:java -Dexec.mainClass="com.example.prototype.Main" -
运行测试:
bashmvn test -
打包项目:
bashmvn package
4. 核心概念
- 原型接口:Shape抽象类实现了Cloneable接口
- 具体原型:Circle和Rectangle类实现具体的克隆逻辑
- 原型管理器:ShapeCache类负责存储和提供原型对象的克隆
- 深拷贝与浅拷贝:
- 浅拷贝:基本类型字段被复制,引用类型字段共享同一对象
- 深拷贝:所有字段都被复制,包括引用类型字段
- 适用场景
- 当创建对象的成本较高时(如数据库查询、复杂计算)
- 当需要创建大量相似对象时
- 当需要避免使用类的构造函数时
- 当系统需要独立于产品的创建、构成和表示时