设计模式——原型模式

原型模式 (Prototype Pattern)

什么是原型模式?

原型模式是一种创建型设计模式,它允许你通过复制现有对象来创建新对象,而不是通过实例化类来创建。

简单来说:原型模式就是通过克隆(复制)现有对象来创建新对象。

生活中的例子

想象一下:

  • 复印文档:复印一份已有的文档,而不是重新写一份
  • 克隆生物:克隆一只羊,而不是重新培育一只
  • 复制粘贴:复制一段文字,而不是重新输入

为什么需要原型模式?

传统方式的问题

java 复制代码
// 创建对象
User user1 = new User("张三", 25);
User user2 = new User("张三", 25);  // 需要重新设置属性

问题

  1. 重复代码:需要重复设置相同的属性
  2. 创建复杂:如果对象创建过程复杂,需要重复执行
  3. 性能开销:如果对象创建耗时,会影响性能

原型模式的优势

java 复制代码
// 克隆对象
User user1 = new User("张三", 25);
User user2 = user1.clone();  // 直接克隆,无需重新设置属性

优势

  1. 简化创建:通过克隆简化对象的创建
  2. 提高性能:避免重复执行复杂的创建过程
  3. 动态创建:可以在运行时动态创建对象

原型模式的结构

复制代码
┌─────────────────────┐
│    Prototype        │  原型接口
├─────────────────────┤
│ + clone(): Object   │
└──────────┬──────────┘
           │ 实现
           ├──┬──────────────────┬──────────────┐
           │                    │              │
┌──────────┴──────┐  ┌───────────┴───────┐  ┌───┴────────┐
│ ConcreteProto1   │  │ ConcreteProto2    │  │ ...       │  具体原型
├─────────────────┤  ├───────────────────┤  ├────────────┤
│ + clone(): Obj   │  │ + clone(): Obj    │  │            │
└─────────────────┘  └───────────────────┘  └────────────┘

代码示例

1. 定义原型接口

java 复制代码
/**
 * 原型接口
 */
public interface Prototype {
    /**
     * 克隆方法
     */
    Prototype clone();
}

2. 定义地址类(引用类型)

java 复制代码
/**
 * 地址类(引用类型,用于演示浅拷贝和深拷贝)
 */
public class Address implements Cloneable {
    private String city;
    private String district;
    
    public Address(String city, String district) {
        this.city = city;
        this.district = district;
    }
    
    // Getter和Setter方法
    public String getCity() {
        return city;
    }
    
    public void setCity(String city) {
        this.city = city;
    }
    
    public String getDistrict() {
        return district;
    }
    
    public void setDistrict(String district) {
        this.district = district;
    }
    
    @Override
    public String toString() {
        return city + "市" + district;
    }
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

3. 实现具体原型

java 复制代码
/**
 * 用户类(实现原型接口和Cloneable接口)
 */
public class User implements Prototype, Cloneable {
    private String name;
    private int age;
    private Address address;
    
    public User(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }
    
    /**
     * 浅拷贝
     */
    @Override
    public User clone() {
        try {
            return (User) super.clone();
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }
    
    /**
     * 深拷贝
     */
    public User deepClone() {
        try {
            User user = (User) super.clone();
            user.address = (Address) address.clone();
            return user;
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }
    
    // Getter和Setter方法
    public String getName() {
        return name;
    }
    
    public int getAge() {
        return age;
    }
    
    public Address getAddress() {
        return address;
    }
    
    @Override
    public String toString() {
        return "User{name='" + name + "', age=" + age + ", address=" + address + "}";
    }
}

4. 使用原型

java 复制代码
/**
 * 原型模式测试类
 * 演示浅拷贝和深拷贝的区别
 */
public class PrototypeTest {
    
    public static void main(String[] args) {
        System.out.println("=== 原型模式测试 ===\n");
        
        // 创建原始对象
        Address address = new Address("北京", "朝阳区");
        User originalUser = new User("张三", 25, address);
        System.out.println("原始用户: " + originalUser);
        
        System.out.println("\n--- 浅拷贝 ---");
        User shallowCopy = originalUser.clone();
        System.out.println("浅拷贝用户: " + shallowCopy);
        System.out.println("原始用户 == 浅拷贝用户: " + (originalUser == shallowCopy));
        System.out.println("原始地址 == 浅拷贝地址: " + (originalUser.getAddress() == shallowCopy.getAddress()));
        
        // 修改浅拷贝的地址
        shallowCopy.getAddress().setCity("上海");
        System.out.println("\n修改浅拷贝的地址后:");
        System.out.println("原始用户: " + originalUser);
        System.out.println("浅拷贝用户: " + shallowCopy);
        System.out.println("注意:原始用户的地址也被修改了(浅拷贝问题)");
        
        System.out.println("\n--- 深拷贝 ---");
        User deepCopy = originalUser.deepClone();
        System.out.println("深拷贝用户: " + deepCopy);
        System.out.println("原始用户 == 深拷贝用户: " + (originalUser == deepCopy));
        System.out.println("原始地址 == 深拷贝地址: " + (originalUser.getAddress() == deepCopy.getAddress()));
        
        // 修改深拷贝的地址
        deepCopy.getAddress().setCity("广州");
        System.out.println("\n修改深拷贝的地址后:");
        System.out.println("原始用户: " + originalUser);
        System.out.println("深拷贝用户: " + deepCopy);
        System.out.println("注意:原始用户的地址没有被修改(深拷贝正确)");
        
        System.out.println("\n=== 原型模式的优势 ===");
        System.out.println("1. 简化创建:通过克隆简化对象的创建");
        System.out.println("2. 提高性能:避免重复执行复杂的创建过程");
        System.out.println("3. 动态创建:可以在运行时动态创建对象");
        System.out.println("4. 隐藏细节:隐藏对象创建的细节");
    }
}

浅拷贝 vs 深拷贝

浅拷贝

只复制基本类型和对象的引用,不复制引用对象本身。

java 复制代码
public class Address implements Cloneable {
    private String city;
    
    // ...
}

public class User implements Cloneable {
    private String name;
    private Address address;  // 引用类型
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();  // 浅拷贝,只复制address的引用
    }
}

问题:修改克隆对象的address会影响原对象。

深拷贝

复制所有对象,包括引用对象。

java 复制代码
public class User implements Cloneable {
    private String name;
    private Address address;
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        User user = (User) super.clone();
        user.address = (Address) address.clone();  // 深拷贝
        return user;
    }
}

原型模式的优点

  1. 简化创建:通过克隆简化对象的创建
  2. 提高性能:避免重复执行复杂的创建过程
  3. 动态创建:可以在运行时动态创建对象
  4. 隐藏细节:隐藏对象创建的细节

原型模式的缺点

  1. 深拷贝复杂:实现深拷贝可能比较复杂
  2. 类依赖:类必须实现Cloneable接口
  3. 循环引用:处理循环引用比较困难

适用场景

  1. 对象创建复杂:对象的创建过程复杂或耗时
  2. 对象相似:需要创建多个相似的对象
  3. 保护性拷贝:需要保护原对象不被修改
  4. 动态创建:需要在运行时动态创建对象

常见应用场景

  • 对象池:对象池中的对象克隆
  • 文档编辑:复制粘贴文档内容
  • 游戏开发:克隆游戏角色或道具
  • 配置管理:复制配置对象

使用建议

  • 对象创建复杂:使用原型模式
  • 需要多个相似对象:使用原型模式
  • 简单对象:直接使用构造函数即可

注意事项

⚠️ 原型模式虽然有用,但要注意:

  • 区分浅拷贝和深拷贝
  • 处理循环引用
  • 考虑使用序列化实现深拷贝
相关推荐
杨充12 小时前
10.可测试性实战设计
设计模式·开源·代码规范
杨充12 小时前
9.重构十二式的实战
设计模式·开源·代码规范
杨充12 小时前
6.设计原则的全景图
设计模式·开源·全栈
杨充12 小时前
2.面向对象的特性
设计模式
杨充12 小时前
7.SOLID原则案例汇
设计模式·开源·全栈
杨充12 小时前
8.反模式与坏味道
设计模式·开源·代码规范
杨充13 小时前
3.接口vs抽象类比较
设计模式
咖啡八杯16 小时前
文法、BNF与AST
java·设计模式·解释器模式·ast·文法
咖啡八杯1 天前
GoF设计模式——解释器模式
java·后端·spring·设计模式