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