设计模式-原型模式

要理解设计模式中的原型模式,我们可以从其核心思想入手:通过复制(克隆)一个已存在的对象(原型)来创建新对象,而非通过构造方法重新初始化。它的本质是利用对象的自我复制能力,简化相似对象的创建过程,尤其适合创建成本高(如初始化步骤复杂、依赖外部资源)或需要频繁创建的场景。

一、原型模式的核心角色

原型模式包含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对象,避免此问题。

四、原型模式的优点

  1. 简化对象创建:无需重复执行复杂的初始化逻辑,通过克隆直接生成新对象,提高创建效率。
  2. 灵活性高:客户端只需通过clone()方法即可创建对象,无需依赖具体类(符合“依赖倒置原则”)。
  3. 便于扩展:新增具体原型时,只需实现clone()方法,无需修改客户端或原型管理器代码(符合“开闭原则”)。

通过这个例子,我们可以清晰看到:原型模式通过对象克隆实现了“以对象造对象”,特别适合需要频繁创建相似对象且初始化成本高的场景(如游戏角色、文档元素、复杂配置对象等)。

posted @ 2025-11-05 09:55  fishyy  阅读(2)  评论(0)    收藏  举报