基于原型模式和享元模式完成不同分层POJO 之间的数据拷贝
Once you understand the design patterns and have had an "Aha!" (and not just a "Huh?") experience with them, you won't ever think about object-oriented design in the same way. You'll have insights that can make your own designs more flexible,
modular, reusable, and understandable—which is why you're interested in object-oriented technology in the first place, right? —— GOF
一旦你理解了设计模式并且有了一种“Aha!”(而不是“Huh?”)的应用经验和体验后,你将用一种非同寻常的方式思考面向对象设计。你将拥有一种深刻的洞察力,以帮助你设计出更加灵活的、模块化的、可复用的和易理解的软件 ——这也是你为何着迷于面向对象技术的源动力,不是吗? —— 《设计模式》作者四人帮
你在初学 Java 的时候,是不是遇到过这样的场景,不经意间写过这样的代码:
原型模式与享元模式有一些相似的地方,但本质是不同的。在 GOF的书里,原型模式是创建型模式,而享元模式则属于结构姓模式。从性能优化的角度分析,原型模式是在创建多个实例时,对创建过程的性能进行调优;享元模式是用减少创建实例的方式,来调优系统性能。
原型模式的一个经典应用场景是优化创建重复对象:
int i = 1000;
while(i > 0) {
Student student = new Student();
i--;
}
- 自己实现属性拷贝太繁琐,代码冗余
- apache 的 Beanuitils: 反射
- apache 的 PropetiesUtils: 反射
- SPring 的 beanutils: 反射
- cglib 的 BeanCopier: 动态代理,性能很高,达到上面反射方式的几十倍甚至是数百倍
- 原型模式和享元模式的设计模式讲解
- 代码实现
- 优化深度克隆:List: 其实深拷贝就是基于浅拷贝来递归实现具体的每个对象
- CgLib 底层实现
new一个对象和clone一个对象,性能差在哪里呢?文中提到直接从内存复制二进制这里不是很理解
作者回复: 一个对象通过new创建的过程为:
1、在内存中开辟一块空间;
2、在开辟的内存空间中创建对象;
3、调用对象的构造函数进行初始化对象。而一个对象通过clone创建的过程为:
1、根据原对象内存大小开辟一块内存空间;
2、复制已有对象,克隆对象中所有属性值。相对new来说,clone少了调用构造函数。如果构造函数中存在大量属性初始化或大对象,则使用clone的复制对象的方式性能会好一些。
引入 pom:
<!-- cglib的BeanCopier需要的依赖 -->
<dependency>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>asm</groupId>
<artifactId>asm-commons</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>asm</groupId>
<artifactId>asm-util</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2.2</version>
</dependency>
public class BeanCopierUtils {
/**
* BeanCopier缓存
*/
public static Map<String, BeanCopier> beanCopierCacheMap = new HashMap<String, BeanCopier>();
/**
* 将source对象的属性拷贝到target对象中去
* @param source source对象
* @param target target对象
*/
public static void copyProperties(Object source, Object target){
String cacheKey = source.getClass().toString() + target.getClass().toString();
BeanCopier beanCopier = null;
if (!beanCopierCacheMap.containsKey(cacheKey)) {
synchronized(BeanCopierUtils.class) {
if (!beanCopierCacheMap.containsKey(cacheKey)) {
beanCopier = BeanCopier.create(source.getClass(), target.getClass(), false);
beanCopierCacheMap.put(cacheKey, beanCopier);
}
}
} else {
beanCopier = beanCopierCacheMap.get(cacheKey);
}
beanCopier.copy(source, target, null);
}
}
参考: