设计模式随笔-原型模式
原型模式
使用场景
原型模式即使用深拷贝生成新的对象,避免重新创建对象所产生的巨大资源消耗
- 当某一对象创建耗费资源较大时,推荐使用原型模式实现
- new 一个对象过程繁琐,或者需要准备数据付出较大代价时,推荐使用原型模式
- 一个对象有多个修改者时,推荐使用原型场景
- 需要保存对象快照,供后期使用时(也可通过序列化实现)
实现关键
实体实现Cloneable接口,重写clone方法
注意:
当类存在非基础类型属性时,须在属性类上也实现Cloneable接口,并且类的clone方法需要单独实现属性对象的拷贝赋值,即通过属性类的递归克隆实现类clone方法为深拷贝,避免属性对象产生变化导致的踩内存现象
模式实现
优点
- 用对象克隆代替对象创建,降低创建对象带来的较大资源开销(空间时间开销大、创建繁琐)
缺点
- 类clone方法实现须准确,否则修改对象时可能导致同步修改克隆对象的情况
@Data
@Slf4j
@AllArgsConstructor
class Person implements Cloneable {
private String name;
private int age;
/**
* 该属性非基本类型,实现clone方法时需要单独处理,且该属性的类需要实现Cloneable接口
* 当该属性类同样有非基本类型属性时,需要递归实现Cloneable接口,重写clone方法
**/
private Address address;
public Person clone() {
Person person = null;
Object obj = null;
try {
obj = super.clone();
} catch (CloneNotSupportedException e) {
log.error("Person clone failed");
}
if (obj instanceof Person) {
person = (Person) obj;
}
// 为保证深拷贝,需将对象属性进行单独拷贝,然后赋值
person.setAddress(address.clone());
return person;
}
@Data
@AllArgsConstructor
static class Address implements Cloneable {
private String addressStr;
public Address clone() {
Address address = null;
Object obj = null;
try {
obj = super.clone();
} catch (CloneNotSupportedException e) {
log.error("Person clone failed");
}
if (obj instanceof Address) {
address = (Address) obj;
}
return address;
}
}
}
测试用例
@Slf4j
public class PrototypePattern {
public static void main(String[] args) {
Person.Address address = new Person.Address("Gansu");
Person person = new Person("ZhangSun", 18, address);
Person personClone = person.clone();
address.setAddressStr("ZheJiang");
log.info("Person :{}", JSONObject.toJSONString(person));
log.info("Person Clone :{}", JSONObject.toJSONString(personClone));
}
}
1.正确实现clone方法时
2.当以下代码块被注释时,即未对对象属性做特别处理,就会导致修改对象时克隆对象被同步修改的情况出现
// 为保证深拷贝,需将对象属性进行单独拷贝,然后赋值
person.setAddress(address.clone());