设计模式-原型模式
要理解设计模式中的原型模式,我们可以从其核心思想入手:通过复制(克隆)一个已存在的对象(原型)来创建新对象,而非通过构造方法重新初始化。它的本质是利用对象的自我复制能力,简化相似对象的创建过程,尤其适合创建成本高(如初始化步骤复杂、依赖外部资源)或需要频繁创建的场景。
一、原型模式的核心角色
原型模式包含3个核心角色,各自职责如下:
| 角色 | 职责描述 |
|---|---|
| 抽象原型(Prototype) | 声明克隆方法的接口或抽象类,通常包含一个clone()方法,定义对象复制的规范。 |
| 具体原型(ConcretePrototype) | 实现抽象原型的clone()方法,完成自身的复制逻辑(浅克隆或深克隆)。 |
| 客户端(Client) | 通过调用原型对象的clone()方法,复制出新的对象,无需关心具体创建细节。 |
二、Java代码演示
我们以“文档编辑器中的图形元素”为例(如圆形、矩形,用户经常需要复制这些图形),演示原型模式的实现。Java中通过Cloneable接口和clone()方法原生支持原型模式。
1. 定义抽象原型(Prototype)
声明克隆方法,这里直接使用Java的Cloneable接口(标记接口,标识对象可克隆),并定义图形的公共属性和方法:
// 抽象原型:图形
public abstract class Shape implements Cloneable {
protected String id; // 图形唯一标识
protected String type; // 图形类型(如圆形、矩形)
// 获取图形类型
public abstract String getType();
// 绘制图形(业务方法)
public void draw() {
System.out.println("绘制" + type + "(ID:" + id + ")");
}
// 设置ID
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
// 克隆方法(核心)
@Override
public Object clone() {
Object clone = null;
try {
// 调用Object的native clone方法,实现浅克隆
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
2. 定义具体原型(ConcretePrototype)
实现抽象原型,定义具体图形的属性和克隆逻辑:
// 具体原型1:圆形
public class Circle extends Shape {
private int radius; // 半径(圆形特有属性)
public Circle() {
this.type = "圆形";
}
@Override
public String getType() {
return type;
}
public int getRadius() {
return radius;
}
public void setRadius(int radius) {
this.radius = radius;
}
// 重写toString,方便查看属性
@Override
public String toString() {
return "Circle{id='" + id + "', type='" + type + "', radius=" + radius + "}";
}
}
// 具体原型2:矩形
public class Rectangle extends Shape {
private int width; // 宽度
private int height; // 高度
public Rectangle() {
this.type = "矩形";
}
@Override
public String getType() {
return type;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
@Override
public String toString() {
return "Rectangle{id='" + id + "', type='" + type + "', width=" + width + ", height=" + height + "}";
}
}
3. 原型管理器(可选,优化原型获取)
创建一个“原型池”管理所有原型对象,客户端无需手动创建原型,直接从池获取并克隆:
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();
circle.setId("1");
circle.setRadius(10); // 原型的默认半径
shapeMap.put(circle.getId(), circle);
// 创建矩形原型并缓存
Rectangle rectangle = new Rectangle();
rectangle.setId("2");
rectangle.setWidth(20); // 原型的默认宽度
rectangle.setHeight(15); // 原型的默认高度
shapeMap.put(rectangle.getId(), rectangle);
}
// 从原型池获取原型并克隆
public static Shape getShape(String shapeId) {
Shape cachedShape = shapeMap.get(shapeId);
// 克隆原型,返回新对象
return (Shape) cachedShape.clone();
}
}
4. 客户端(Client)测试
通过克隆原型对象创建新图形,验证克隆效果:
public class Client {
public static void main(String[] args) {
// 1. 初始化原型池
ShapeCache.loadCache();
// 2. 克隆圆形原型(ID=1)
Shape circleClone1 = ShapeCache.getShape("1");
circleClone1.setId("101"); // 修改克隆对象的ID(不影响原型)
((Circle) circleClone1).setRadius(15); // 修改克隆对象的半径
System.out.println("克隆的圆形1:" + circleClone1);
circleClone1.draw();
// 3. 再次克隆圆形原型
Shape circleClone2 = ShapeCache.getShape("1");
circleClone2.setId("102");
((Circle) circleClone2).setRadius(20);
System.out.println("克隆的圆形2:" + circleClone2);
circleClone2.draw();
// 4. 克隆矩形原型(ID=2)
Shape rectangleClone1 = ShapeCache.getShape("2");
rectangleClone1.setId("201");
((Rectangle) rectangleClone1).setWidth(25);
System.out.println("克隆的矩形1:" + rectangleClone1);
rectangleClone1.draw();
// 5. 验证克隆对象与原型是否为不同实例
Shape originalCircle = ShapeCache.getShape("1"); // 注意:这里获取的是克隆的原型副本,原原型仍在池中
System.out.println("圆形原型与克隆1是否为同一对象:" + (originalCircle == circleClone1)); // false
}
}
输出结果:
克隆的圆形1:Circle{id='101', type='圆形', radius=15}
绘制圆形(ID:101)
克隆的圆形2:Circle{id='102', type='圆形', radius=20}
绘制圆形(ID:102)
克隆的矩形1:Rectangle{id='201', type='矩形', width=25, height=15}
绘制矩形(ID:201)
圆形原型与克隆1是否为同一对象:false
三、原型模式的关键细节:浅克隆与深克隆
- 浅克隆:默认的
super.clone()是浅克隆,只复制对象本身及基本类型属性,引用类型属性(如对象、数组)仅复制引用(新对象与原对象共享引用类型数据)。 - 深克隆:需手动复制引用类型属性,确保新对象与原对象的引用类型属性完全独立(可通过序列化实现)。
例如,若Shape类有一个Point类型的坐标属性(引用类型),浅克隆会导致原对象和克隆对象共享同一个Point,修改其中一个会影响另一个;深克隆则会创建新的Point对象,避免此问题。
四、原型模式的优点
- 简化对象创建:无需重复执行复杂的初始化逻辑,通过克隆直接生成新对象,提高创建效率。
- 灵活性高:客户端只需通过
clone()方法即可创建对象,无需依赖具体类(符合“依赖倒置原则”)。 - 便于扩展:新增具体原型时,只需实现
clone()方法,无需修改客户端或原型管理器代码(符合“开闭原则”)。
通过这个例子,我们可以清晰看到:原型模式通过对象克隆实现了“以对象造对象”,特别适合需要频繁创建相似对象且初始化成本高的场景(如游戏角色、文档元素、复杂配置对象等)。

浙公网安备 33010602011771号