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);  
    }  
  
}  

参考:

  1. Design Patterns: Elements of Reusable Object-Oriented Software
  2. Java性能调优实战