原型模式

什么是原型模式

Java原型模式(Prototype Pattern)是一种创建型设计模式,其核心理念在于通过复制(克隆)已有的对象来创建新的对象,而不是通过构造函数来创建。
该模式可以显著提高对象创建的效率,特别是在需要频繁创建对象或对象创建过程较为复杂的场景下。

在原型模式中,原型对象作为基础对象,其他对象通过复制这个原型对象来创建新的实例。复制过程可以是浅克隆或深克隆。

  • 浅克隆创建一个新对象,新对象的属性和原对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
  • 深克隆则更为彻底,不仅创建新对象,而且属性中引用的其他对象也会被克隆,不再指向原有对象的内存地址。

使用场景及特点

  • 当通过new产生一个对象需要非常反锁的数据准备及访问权限时,则可以使用原型模式
  • 就是java中的克隆技术,以某个对象为原型,复制出新的对象。显然,新的对象具备原型对象的特点。
    • 优势:效率高(直接克隆,避免了重新执行构造过程的步骤)
  • 克隆类似于new,但是不同于new。new创建新的对象属性采用的是默认值,克隆对象的属性完全与原型对象相同,并且克隆出的新对象改变不会影响原型对象,然后再修改克隆对象的值。

原型模式实现

  • Cloneable接口和clone方法
  • 原型模式中实现起来最为困难的地方就是内存复制操作,然而在Java中提供了对象的clone()方法替我门做了绝大部分事情。

案例

使用原型模式,必须实现Cloneable接口,重写protected Object clone()方法

浅拷贝

Address.java

//地址
public class Address {
  private String city;

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

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

  @Override
  public String toString() {
    return "Address{" +
            "city='" + city + '\'' +
            '}';
  }
}

Person.java

// 浅拷贝
// 实现Cloneable接口 重写protected Object clone()方法
public class Person implements Cloneable{
  private String name;

  private Address address;

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

  public Address getAddress() {
    return address;
  }

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

  @Override
  protected Object clone() throws CloneNotSupportedException {
    return super.clone();   // 默认浅拷贝
  }

  @Override
  public String toString() {
    return "Person{" +
            "name='" + name + '\'' +
            ", address=" + address +
            '}';
  }
}

TestClient.java

public class TestClient {

    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person("张三",new Address("北京"));
        Person clone = (Person) person.clone();
        System.out.printf("浅拷贝-原型对象:%s%n",person);
        System.out.printf("浅拷贝-拷贝对象值:%s%n",clone);

        System.out.println("======修改原型对象-address======");
        person.getAddress().setCity("重庆");
        System.out.printf("浅拷贝-原型对象:%s%n",person);
        System.out.printf("浅拷贝-拷贝对象值:%s%n",clone);

        System.out.println("======修改拷贝对象-address======");
        clone.getAddress().setCity("广州");
        System.out.printf("浅拷贝-原型对象:%s%n",person);
        System.out.printf("浅拷贝-拷贝对象值:%s%n",clone);
    }
}

执行结果:

03-JAVA设计模式-原型模式-LMLPHP

图解

03-JAVA设计模式-原型模式-LMLPHP

深拷贝

Address.java 实现Cloneable接口,重新clone()

// 地址
public class Address implements Cloneable{
    private String city;

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

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

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

    @Override
    public String toString() {
        return "Address{" +
                "city='" + city + '\'' +
                '}';
    }
}

修改Person clone()方法

// 深拷贝
public class Person implements Cloneable{
    private String name;

    private Address address;

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

    public Address getAddress() {
        return address;
    }

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

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person clone = (Person) super.clone();
        clone.address = (Address) this.getAddress().clone();
        return clone;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", address=" + address +
                '}';
    }
}

TestClient2.java

public class TestClient2 {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person("张三",new Address("北京"));
        Person clone = (Person) person.clone();
        System.out.printf("深拷贝-原型对象:%s%n",person);
        System.out.printf("深拷贝-拷贝对象值:%s%n",clone);

        System.out.println("======修改原型对象-address======");
        person.getAddress().setCity("重庆");
        System.out.printf("深拷贝-原型对象:%s%n",person);
        System.out.printf("深拷贝-拷贝对象值:%s%n",clone);

        System.out.println("======修改拷贝对象-address======");
        clone.getAddress().setCity("广州");
        System.out.printf("深拷贝-原型对象:%s%n",person);
        System.out.printf("深拷贝-拷贝对象值:%s%n",clone);
    }
}

执行结果:

03-JAVA设计模式-原型模式-LMLPHP

图解

03-JAVA设计模式-原型模式-LMLPHP

利用序列化和反序列化完成深克隆

通过序列化及反序列化实现深克隆必须实现Serializable接口
Person.java

public class Person implements Serializable {

  private String name;

  private Address address;

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

  public Address getAddress() {
    return address;
  }

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

  @Override
  public String toString() {
    return "Person{" +
            "name='" + name + '\'' +
            ", address=" + address +
            '}';
  }
}

Address.java

// 地址
public class Address implements Serializable {

    private String city;

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

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

    @Override
    public String toString() {
        return "Address{" +
                "city='" + city + '\'' +
                '}';
    }
}

TestClient3.java

public class TestClient3 {
    public static void main(String[] args) throws CloneNotSupportedException, Exception {
        Person person = new Person("张三",new Address("北京"));
        // 通过序列化 反序列化实现深拷贝

        byte[] bytes = null;
        Person clone = null;

        // 序列化
        try( ByteArrayOutputStream baos = new ByteArrayOutputStream();
             ObjectOutputStream oos = new ObjectOutputStream(baos);){
            oos.writeObject(person);
            bytes = baos.toByteArray();
        }

        // 反序列化
        try( ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
             ObjectInputStream ois = new ObjectInputStream(bais);){
            clone = (Person) ois.readObject();
        }

        System.out.printf("深拷贝-原型对象:%s%n",person);
        System.out.printf("深拷贝-拷贝对象值:%s%n",clone);

        System.out.println("======修改原型对象-address======");
        person.getAddress().setCity("重庆");
        System.out.printf("深拷贝-原型对象:%s%n",person);
        System.out.printf("深拷贝-拷贝对象值:%s%n",clone);

        System.out.println("======修改拷贝对象-address======");
        clone.getAddress().setCity("广州");
        System.out.printf("深拷贝-原型对象:%s%n",person);
        System.out.printf("深拷贝-拷贝对象值:%s%n",clone);
    }
}

执行结果:

03-JAVA设计模式-原型模式-LMLPHP

gitee源码

04-09 05:55