原型设计模式

原型模式

什么是原型模式

原型模式(Prototype),用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象

原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需知道任何创建的细节

示例

在 Java 中实现原型模式,我们通常会使用 Cloneable 接口和 clone() 方法来创建对象的副本。以下是一个使用原型模式编写的示例代码,以创建员工(Employee)对象的克隆为例:

1.首先定义一个实现了 Cloneable 接口的员工类 Employee,并重写 clone() 方法:

import java.util.Date;

public class Employee implements Cloneable {
    private String name;
    private int id;
    private double salary;
    private Date hireDate;

    public Employee(String name, int id, double salary, Date hireDate) {
        this.name = name;
        this.id = id;
        this.salary = salary;
        this.hireDate = (Date) hireDate.clone();  // 防止浅拷贝时日期对象引用共享
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public void setHireDate(Date hireDate) {
        this.hireDate = (Date) hireDate.clone();  // 防止浅拷贝时日期对象引用共享
    }

    public String getName() {
        return name;
    }

    public int getId() {
        return id;
    }

    public double getSalary() {
        return salary;
    }

    public Date getHireDate() {
        return (Date) hireDate.clone();  // 防止浅拷贝时日期对象引用共享
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

这里,员工类实现了 Cloneable 接口,并重写了 clone() 方法。由于 Date 类型的属性可能引起浅拷贝问题,我们在构造器和 getter/setter 中使用 clone() 方法复制 hireDate,确保深拷贝。

2.在客户端代码中,创建一个员工对象,并使用 clone() 方法创建其副本:

import java.text.SimpleDateFormat;
import java.util.Date;

public class PrototypeDemo {
    public static void main(String[] args) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        try {
            // 创建原始员工对象
            Employee original = new Employee("Alice", 1, 5000.0, sdf.parse("2023-06-9"));

            // 使用 clone() 方法创建员工副本
            Employee cloned = (Employee) original.clone();

            // 改变原始员工的信息
            original.setName("Bob");
            original.setSalary(6000.0);
            original.setHireDate(sdf.parse("2023-0¾-10"));

            // 输出原始员工和克隆员工的信息
            System.out.println("Original Employee:");
            System.out.println("Name: " + original.getName());
            System.out.println("ID: " + original.getId());
            System.out.println("Salary: " + original.getSalary());
            System.out.println("Hire Date: " + sdf.format(original.getHireDate()));

            System.out.println("\nCloned Employee:");
            System.out.println("Name: " + cloned.getName());
            System.out.println("ID: " + cloned.getId());
            System.out.println("Salary: " + cloned.getSalary());
            System.out.println("Hire Date: " + sdf.format(cloned.getHireDate()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

什么是深拷贝

深拷贝是指在复制对象时,不仅复制对象本身,还递归地复制其所有包含的引用对象,直到所有的嵌套层次的对象都被复制为止。这意味着深拷贝创建的新对象与原对象具有完全相同的结构和数据,但它们在内存中占用独立的空间,互不影响。当对任何一个对象进行修改时,都不会影响到另一个对象,因为它们的内部状态(包括所引用对象的状态)都是独立存储的。

在 Java 中实现深拷贝,可以采用以下几种常见方法:

  1. 实现 Cloneable 接口并重写 clone() 方法
需要注意处理引用类型的属性,确保它们也被深拷贝。
  1. 使用序列化(Serializable)和反序列化
通过 ObjectOutputStream 写入字节流,再使用 ObjectInputStream 读取字节流,实现深拷贝
  1. 手动复制所有属性
对于简单对象,可以直接创建新对象并逐一复制每个属性值;对于复杂对象,需要递归地复制所有嵌套的对象。

这里我们以实现 Cloneable 接口并重写 clone() 方法的方式,编写一个包含员工(Employee)和地址(Address)类的深拷贝示例:

public class Address implements Cloneable {
    private String street;
    private String city;

    public Address(String street, String city) {
        this.street = street;
        this.city = city;
    }

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

Employee 类:

public class Employee implements Cloneable {
    private String name;
    private int age;
    private Address address;

    public Employee(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = (Address) address.clone();  // 防止浅拷贝
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Address getAddress() {
        return (Address) address.clone();  // 防止浅拷贝
    }

    public void setAddress(Address address) {
        this.address = (Address) address.clone();  // 防止浅拷贝
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Employee clonedEmployee = (Employee) super.clone();
        clonedEmployee.address = (Address) address.clone();  // 深拷贝地址对象
        return clonedEmployee;
    }
}

客户端代码

public class DeepCopyDemo {
    public static void main(String[] args) {
        Address originalAddress = new Address("123 Main St", "New York");
        Employee originalEmployee = new Employee("John Doe", 30, originalAddress);

        try {
            Employee clonedEmployee = (Employee) originalEmployee.clone();

            // 修改克隆对象的属性
            clonedEmployee.setName("Jane Smith");
            clonedEmployee.getAddress().setCity("Los Angeles");

            System.out.println("Original Employee:");
            System.out.println("Name: " + originalEmployee.getName());
            System.out.println("Age: " + originalEmployee.getAge());
            System.out.println("Address: " + originalEmployee.getAddress().getStreet() + ", " + originalEmployee.getAddress().getCity());

            System.out.println("\nCloned Employee:");
            System.out.println("Name: " + clonedEmployee.getName());
            System.out.println("Age: " + clonedEmployee.getAge());
            System.out.println("Address: " + clonedEmployee.getAddress().getStreet() + ", " + clonedEmployee.getAddress().getCity());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

运行 DeepCopyDemo 类的 main 方法,输出结果应为:

Original Employee:
Name: John Doe
Age: 30
Address: 123 Main St, New York

Cloned Employee:
Name: Jane Smith
Age: 30
Address: 123 Main St, Los Angeles

在这个示例中,我们通过实现 Cloneable 接口并重写 clone() 方法,实现了 Employee 和 Address 类的深拷贝。当修改克隆对象的属性时,原对象的属性保持不变,证明了深拷贝的成功。

什么是浅拷贝

浅拷贝是指在复制对象时,只复制对象本身,而不复制其包含的引用对象。也就是说,如果一个对象包含其他对象的引用,那么浅拷贝只会复制这些引用,而不是复制引用所指向的对象。结果是,新旧对象在内存中占据不同的位置,但它们内部的引用对象仍然指向同一块内存空间。因此,当其中一个对象修改其引用对象的状态时,会影响到另一个对象,因为它们共享了同一份数据。

假设我们有以下两个类:Person 类和 Address 类。Person 类包含一个 name 字符串属性和一个 address 引用属性,指向一个 Address 对象。

public class Address {
    private String street;
    private String city;

    public Address(String street, String city) {
        this.street = street;
        this.city = city;
    }

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }
}
public class Person {
    private String name;
    private Address address;

    public Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    // 实现浅拷贝
    public Person shallowCopy() {
        return new Person(name, address);
    }
}

客户端代码

public class ShallowCopyDemo {
    public static void main(String[] args) {
        Address originalAddress = new Address("123 Main St", "New York");
        Person originalPerson = new Person("John Doe", originalAddress);

        Person copiedPerson = originalPerson.shallowCopy();

        // 修改复制对象的地址属性
        copiedPerson.getAddress().setCity("Los Angeles");

        System.out.println("Original Person:");
        System.out.println("Name: " + originalPerson.getName());
        System.out.println("Address: " + originalPerson.getAddress().getStreet() + ", " + originalPerson.getAddress().getCity());

        System.out.println("\nCopied Person:");
        System.out.println("Name: " + copiedPerson.getName());
        System.out.println("Address: " + copiedPerson.getAddress().getStreet() + ", " + copiedPerson.getAddress().getCity());
    }
}

运行 ShallowCopyDemo 类的 main 方法,输出结果应为:

Original Person:
Name: John Doe
Address: 123 Main St, Los Angeles

Copied Person:
Name: John Doe
Address: 123 Main St, Los Angeles

在这个示例中,我们通过 Person 类的 shallowCopy() 方法实现了浅拷贝。当修改复制对象的地址属性时,原对象的地址属性也被同步修改,表明它们共享了同一个 Address 对象。这就是浅拷贝的表现:虽然 originalPerson 和 copiedPerson 是两个不同的 Person 对象,但它们的 address 属性指向的是同一份 Address 数据。

相关推荐

  1. 设计模式原型模式

    2024-04-12 01:54:02       37 阅读
  2. 设计模式——原型模式

    2024-04-12 01:54:02       31 阅读
  3. 设计模式-原型模式

    2024-04-12 01:54:02       35 阅读
  4. 设计模式-原型模式

    2024-04-12 01:54:02       34 阅读
  5. 设计模式-原型模式

    2024-04-12 01:54:02       25 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-12 01:54:02       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-12 01:54:02       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-12 01:54:02       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-12 01:54:02       18 阅读

热门阅读

  1. 算法| ss 合并区间

    2024-04-12 01:54:02       15 阅读
  2. 蓝桥杯——分糖果

    2024-04-12 01:54:02       15 阅读
  3. Esilnt使用记录

    2024-04-12 01:54:02       13 阅读
  4. 【IC前端虚拟项目】SDC文件编写与DC综合环境组织

    2024-04-12 01:54:02       14 阅读
  5. 钩子函数和副作用

    2024-04-12 01:54:02       13 阅读
  6. jquery 数字金额转化为大写金额

    2024-04-12 01:54:02       14 阅读
  7. 从企业开发流程到使用场景解析 git vs svn

    2024-04-12 01:54:02       16 阅读
  8. Android app如何禁止运行在模拟器中

    2024-04-12 01:54:02       16 阅读
  9. Python编程学院:揭秘面向对象的魔法

    2024-04-12 01:54:02       12 阅读