用简单通俗的话来记录自己对架构的理解
1.为什么
(1)一种更高效的对象创建方式,利用原型对象来复制产生新的对象:这种方式的创建更高效,避免了new这种方式的耗时,当然,也可以避免耗时操作的创建(比如数据库的查询)
(2)特殊需求的要求,比如需求:对原始对象进行1,2,3步的处理,而在第4步却还要使用原始对象。
(3)架构需要:为了模块隔离对外暴露隔离API
比如Java中的ArrayList、Intent等
@Override
public Object clone() {
return new Intent(this);
}
/**
* Returns a shallow copy of this <tt>ArrayList</tt> instance. (The
* elements themselves are not copied.)
*
* @return a clone of this <tt>ArrayList</tt> instance
*/
public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
**TODO:**实际上,此处有一个疑问,Intent为啥不像ArrayList使用Clone方式,使用堆内存直接复制?
2.是什么
上类图:
直白一点,就是为了更简单获取对象。
那么在java中的原型模式又分为深克隆和浅克隆;对于一个对象,其成员变量为基本数据和引用数据。浅克隆只是对象的引用的复制,而深克隆则是原始对象的引用数据进行申请内存空间,不是简单的对象的引用。
(1).深克隆
深克隆就是对于对象的基本数据进行复制,引用数据进行申请内存,复制对象数据,而引用指向是变化的。
深克隆的方式有很多种,对于Java中常用的是序列化。之所以序列化,是因为序列化本质是格式的转变,从对象——>序列化——>反序列化——>对象,这个对象是完全重新申请空间创建的。代码如下:
public class PrototypeUtil {
/**
* @description: 通过序列化获取一个深度克隆的对象
* @param prototype
* @return com.lmc.gp12380.pattern.prototype.Prototype
* @date 2019/5/30 21:34
* @author lmc
*/
public static Prototype getSerializInstance(Prototype prototype){
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(prototype);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
Prototype copy = (Prototype)ois.readObject();
bos.flush();
bos.close();
ois.close();
return copy;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}
当然,对于简单的对象,也有同学是循环使用Java中的Clone,只要是引用数据类型,都进行Clone的处理。这种方式太ugly和笨重,所以,不推荐。
(2).浅克隆
浅克隆就是对于成员变量复制,包括基本数据类型和引用数据类型。这样的话,引用数据类型的只是指针引用复制,实际指引对象是不变的。
Java中的实现是通过Cloneale的clone()方法。实际上Clone方法进行了优化,对于new()这个方法,只进行了内存申请的操作,效率要高很多,可以看源码解析。但是,它是如何实现的呢?ASM看源码:
难过的是字节码功底不够,我没咋看懂,回头再研究一下。
3.怎么用
思路:定义一个接口类,实现深浅克隆。
/**
* 接口
**/
public interface Prototype {
/**
* @description: 获取浅克隆对象
* @return java.lang.Object
* @date 2019/5/29 20:35
* @author lmc
*/
Prototype getShallowCloneInstance() throws CloneNotSupportedException;
/**
* @description: 获取深克隆对象
* @return com.lmc.gp12380.pattern.prototype.Prototype
* @date 2019/5/30 21:15
* @author lmc
*/
Prototype getDeepCloneInstance(Prototype prototype);
}
/**
* 序列化实现深克隆
*/
public class PrototypeUtil {
/**
* @description: 通过序列化获取一个深度克隆的对象
* @param prototype
* @return com.lmc.gp12380.pattern.prototype.Prototype
* @date 2019/5/30 21:34
* @author lmc
*/
public static Prototype getSerializInstance(Prototype prototype){
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(prototype);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
Prototype copy = (Prototype)ois.readObject();
bos.flush();
bos.close();
ois.close();
return copy;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}
实现对象实现Clone方法,并暴露新的接口:
```java
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public Prototype getShallowCloneInstance() throws CloneNotSupportedException {
return (Prototype) clone();
}```
4.源码解析
1.克隆比直接创建效率更高吗?
(1)实例:
对象的创建和克隆比对:
long newObjectStart = System.currentTimeMillis();
List<Student> newStudentList = new ArrayList<>();
for (int i =0;i<10000;i++){
Student student = new Student();
student.setAge(10);
student.setName("xl"+i);
newStudentList.add(student);
}
Log.d("haha","newObjectCostTime:"+(System.currentTimeMillis() - newObjectStart));
long cloneObjectStart = System.currentTimeMillis();
List<Student> cloneStudentList = new ArrayList<>();
Student student = new Student();
for (int i =0;i<10000;i++){
Student cloneStudent = (Student) student.clone();
cloneStudent.setAge(10);
cloneStudent.setName("xl"+i);
cloneStudentList.add(student);
}
Log.d("haha","newObjectCostTime:"+(System.currentTimeMillis() - cloneObjectStart));
结果:
2021-02-19 00:21:57.075 9695-9695/xl.com.frameworkdesigndemo D/haha: 1000条数据newObjectCostTime:15
2021-02-19 00:21:57.081 9695-9695/xl.com.frameworkdesigndemo D/haha: 1000条数据cloneObjectCostTime:6
2021-02-19 00:22:26.204 9696-9696/xl.com.frameworkdesigndemo D/haha: 100条数据newObjectCostTime:4
2021-02-19 00:22:26.207 9696-9696/xl.com.frameworkdesigndemo D/haha: 100条数据cloneObjectCostTime:3
(2)本质原因:
从字节码指令集的解读对象创建的流程的解读:
5.巨人肩膀
https://www.cnblogs.com/programmerkaixin/p/10969745.html