原型模式是指通过拷贝原型对象创建新的对象,它在23种设计模式中相对来说简单一些。
原型模式的核心在于拷贝原型对象,JDK的实现拷贝的方式是直接基于内存二进制流进行拷贝,无需再经历耗时的对象初始化过程,性能提升很多。
拷贝的目的是避免复杂的属性赋值和耗时的对象构建。下面来看原型模式的类结构图
从上面的UML图中,我们可以发现原型模式主要包含3个角色:
- 客户(Client):客户类提出创建对象的请求
- 抽象原型(ProtoType):规定拷贝接口
- 原型实现类:(ConcreteProtoType):能被拷贝的对象
相信大家,曾经看到过下面的代码:
这样的代码虽然工整,命名也规范,注释可能写的也全面。这就是原型模式的产生的需求场景。它能帮我解决什么问题呢?
原型模式的需求场景:
1、类初始化消耗资源较多
2、new 产生的一个对象需要繁琐的过程(数据准备,权限访问等)
3、构造函数复杂
4、循环体中产生大量对象时
在 Spring 框架中,原型模式应用非常广泛。例如 scope = "prototype" ,在我们经常用的JSON.parseObject() 也是一种原型模式。
原型模式的Java实现方式可以分2种:浅拷贝和深拷贝。
浅拷贝
<code>@Data
public class User implements Cloneable {
private int age;
private String name;
private List<string> hobbies;
@override
public User clone(){
try {
return (User)super.clone();
} catch (Exception e) {
//TODO: handle exception
return null;
}
}
}/<string>/<code>
通过实现Cloneable接口的Clone() 方法得到拷贝类,改变原型对象age,String值,拷贝对象不会跟着改变,相互独立。但是细心的朋友会发现,调用原型对象hobbies.add()方法添加新元素,拷贝对象的hobbies也会跟着变化。这是为什么呢? 这是因为List<string>属于引用类型成员变量,虽然拷贝形成了新的变量,但是指向的还是内存推中的原List对象。/<string>
深拷贝
<code>@Data
public class User implements Cloneable {
private int age;
private String name;
private List<string> hobbies;
@override
public User clone(){
try {
return (User)super.clone();
} catch (Exception e) {
//TODO: handle exception
return null;
}
}
//clone接口
public User DeepClone(){
try {
User newUser = this.clone();
newUser.hobbies = (List)((ArrayList)newUser.hobbies).clone();
rerurn newUser;
} catch (Exception e) {
//TODO: handle exception
}
}
//反序列化
public User DeepClone2(){
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeeObject(this);
ByteArraryInputStream bis = new ByteArraryInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (User)ois.readObject();
} catch (Exception e) {
//TODO: handle exception
}
}
}/<string>/<code>
有兴趣的朋友可以分别测试deepClone() 和 deepClone2() 方法,都可以实现深度克隆。
通过反序列化可以实现对象深度克隆这个很容易理解。但是对ArrayLis<string>变量做clone(),为什么也能实现深度克隆,我们看一下ArrayList源代码自然就明白了。/<string>
我们发现ArrayList遍历了所有元素,被进行了copy。
总结原型模式
优点:
1、java自带原型模式基于内存二进制流拷贝,比直接new一个对象性能提升很多
2、可以使用深度克隆保存对象的状态,简化创建对象的过程
缺点:
1、需要为每个类配置克隆方法
2、克隆方法位于类的内部,修改代码违背开闭原则
閱讀更多 福星沐浴露 的文章