原型模式
什么是原型模式
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;}@Overridepublic 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;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone(); // 默认浅拷贝}@Overridepublic 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);}
}
执行结果:
图解
浅拷贝时,当修改原型对象时,拷贝的对象引用仍然指向原型对象的引用,因此修改原型对象,会导致拷贝对象的值发生改变
修改拷贝对象的属性时,则会在堆内存中创建一个新的地址存储新设置的值,拷贝对象引用指向新的引用地址,但不会改变原型对象的引用地址。
深拷贝
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;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}@Overridepublic 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;}@Overrideprotected Object clone() throws CloneNotSupportedException {Person clone = (Person) super.clone();clone.address = (Address) this.getAddress().clone();return clone;}@Overridepublic 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);}
}
执行结果:
图解
利用序列化和反序列化完成深克隆
通过序列化及反序列化实现深克隆必须实现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;}@Overridepublic 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;}@Overridepublic 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);}
}
执行结果:
gitee源码
git clone https://gitee.com/dchh/JavaStudyWorkSpaces.git