原型模式
本篇文章是通过看视频学习总结的内容, 如有错误的地方请谅解,并联系博主及时修改,谢谢您的阅读.
何为原型模式?
原型模式可以客观的理解为对象的复制,通过原型模式对原有对象进行复制,对象的复制分为浅克隆
和深克隆
。
适用场景:
- 对象初始化资源比较多
new
关键字创建对象过程复杂- 构造函数逻辑复杂
- 循环过程中创建大量的对象
原型模式的优点:
- 通过原型模式创建的对象不需要再次走
new
关键字,走构造函数去创建对象,而是直接copy
内存中的内容,所以性能很高 - 不走构造函数,完美避开了构造函数的约束
原型模式的缺点:
- 被拷贝的对象中存在对象引用的情况,被引用的对象也需要实现
java.io.Serializable
- 必须实现
java.lang.Cloneable
接口
举个例子:
- 浅克隆实体类
@Setter
@Getter
@ToString
public class ShallowClone implements Serializable,Cloneable {
private String username;
@Override
public Object clone() {
try {
Object clone = super.clone();
return clone;
} catch (Exception ex) {
return null;
}
}
}
- 浅克隆(对象中存在引用,则无法对引用的对象进行拷贝)
public static void main(String[] args) {
ShallowClone shallowClone = new ShallowClone();
shallowClone.setUsername("张三");
ShallowClone clone = (ShallowClone)shallowClone.clone();
clone.setUsername("李四");
// 张三
System.out.println(shallowClone);
// 李四
System.out.println(clone);
}
- 浅克隆对象中加入其他对象的引用
@Setter
@Getter
@ToString
public class ShallowClone implements Serializable, Cloneable {
private String username;
// 加入对象的引用
List<String> hobbys;
@Override
public Object clone() {
try {
Object clone = super.clone();
return clone;
} catch (Exception ex) {
return null;
}
}
}
- 浅克隆加入对象引用
public static void main(String[] args) {
ShallowClone shallowClone = new ShallowClone();
shallowClone.setUsername("张三");
List<String> hobbys = new ArrayList<>();
hobbys.add("唱");
hobbys.add("跳");
hobbys.add("rap");
hobbys.add("篮球");
shallowClone.setHobbys(hobbys);
ShallowClone clone = (ShallowClone)shallowClone.clone();
clone.setUsername("李四");
List<String> cloneHobbys = clone.getHobbys();
cloneHobbys.add("蔡徐坤");
// ShallowClone(username=张三, hobbys=[唱, 跳, rap, 篮球, 蔡徐坤])
System.out.println(shallowClone);
// ShallowClone(username=李四, hobbys=[唱, 跳, rap, 篮球, 蔡徐坤])
System.out.println(clone);
}
- 通过浅克隆对象中加入对象引用,最终被引用的结果是一样的,可以分析得到实现
java.lang.Cloneable
接口只是对对象进行了浅克隆,并非进行对象深克隆,如果被克隆的对象中存在其他对象的引用的时候,那么被克隆出来的值和原来的值是一致的,且内存地址也是相同的,那么被克隆的引用是直接复制了对象的地址,而不是对象中的内容。 - 深克隆
@Setter
@Getter
@ToString
public class DeepEntity implements Cloneable, Serializable {
private String userName;
private String password;
private List<String> phone;
/**
* 序列化和反序列化深克隆
* 性能低, 占用IO,
*
* @return
*/
public DeepEntity serializationDeepClone (){
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (DeepEntity)ois.readObject();
}catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
/**
* FastJson 序列化和反序列化深克隆
* 对象中的对象无法实例化
*
* @return
*/
public DeepEntity JsonDeepClone (){
String json = JSON.toJSONString(this);
return JSON.parseObject(json, DeepEntity.class);
}
/**
* 使用spring-framework 工具类实现深克隆
* @return
*/
public DeepEntity beanUtilDeepClone() {
DeepEntity deepEntity = new DeepEntity();
BeanUtil.copyProperties(this, deepEntity, true);
return deepEntity;
}
}
- 测试三种深克隆方法
package com.example.learn.design.patterns.prototype;
import com.example.learn.design.patterns.prototype.deep.DeepEntity;
import com.example.learn.design.patterns.prototype.shallow.Entity;
import com.example.learn.design.patterns.prototype.shallow.ShallowClone;
import java.util.ArrayList;
import java.util.List;
/**
* 深克隆测试类
* @author zyred
* @createTime 2020/8/27 16:19
**/
public class PrototypeClient {
public static void main(String[] args) {
deepClone ();
}
/**
* 浅克隆
*/
public static void deepClone (){
DeepEntity entity = new DeepEntity();
entity.setPassword("123456");
entity.setUserName("zyred");
List<String> hobbys = new ArrayList<>();
hobbys.add("唱");
hobbys.add("跳");
hobbys.add("rap");
hobbys.add("篮球");
entity.setHobbys(hobbys);
DeepEntity clone = entity.serializationDeepClone();
//DeepEntity clone = entity.JsonDeepClone();
//DeepEntity clone = entity.beanUtilDeepClone();
clone.getHobbys().add("蔡徐坤");
//DeepEntity(userName=zyred, password=123456, hobbys=[唱, 跳, rap, 篮球])
System.out.println("entity: " + entity);
//DeepEntity(userName=zyred, password=123456, hobbys=[唱, 跳, rap, 篮球, 蔡徐坤])
System.out.println("clone: " + clone);
// false
System.out.println(entity.getHobbys() == clone.getHobbys());
}
}
总结:
- 浅克隆是无法克隆对象中被引用的对象,只会复制引用的地址
- 深克隆是对整个对象中的内容无死角的复制,而不是复制引用的地址,在工作中建议适用深拷贝。