前言
原型模式是一种创建型设计模式, 使你能够复制已有对象, 而又无需使代码依赖它们所属的类。
通俗说法,就是将一个类作为原型,然后复制出来另一个类。
使用场景
这么一说,是不是发现我们经常使用?
比如咱们项目中有 BO、DTO、VO,但是在开发过程中,需要各种转换,get/set,一般情况下大家都会使用 BeanUtils
,将一个类的属性值 set 到另一个类的属性值中,然后返回。
当然,也有一个实体直接从头捅到尾的。
关于 BeanUtils 的 copy 方法,各个框架都提供了相关工具,不过 Java 开发手册
有指出 Apache BeanUtils 性能较差
、也推荐了其他框架。
这里介绍的是使用 Cglib BeanCopier。
封装工具类
查看文档,先封装一个工具类:
public class BeanCopierUtils {
private BeanCopierUtils() {
}
/**
* 将source对象的属性拷贝到target对象中去
*
* @param source source对象
* @param target target对象
*/
public static void copyProperties(Object source, Object target) {
BeanCopier beanCopier = BeanCopier.create(source.getClass(), target.getClass(), false);
beanCopier.copy(source, target, null);
}
}
看到这里是不是感觉,如果我使用 BeanCopier
比较频繁,然后每次都 create 创建对象,是不是很麻烦?
所以就想到需要用缓存!
将 BeanCopier 作为一个元
,在各个线程使用的时候,共享。
public class BeanCopierUtils {
private BeanCopierUtils() {
}
/**
* BeanCopier缓存
*/
private static Map CACHE = new HashMap<>();
/**
* 将source对象的属性拷贝到target对象中去
*
* @param source source对象
* @param target target对象
*/
public static void copyProperties(Object source, Object target) {
String cacheKey = source.getClass().getName() + target.getClass().getName();
BeanCopier beanCopier;
if (!CACHE.containsKey(cacheKey)) {
// 进入到这里会创建一个BeanCopier实例并且放在缓存map中
beanCopier = BeanCopier.create(source.getClass(), target.getClass(), false);
CACHE.put(cacheKey, beanCopier);
} else {
beanCopier = CACHE.get(cacheKey);
}
beanCopier.copy(source, target, null);
}
}
然后再代码中就可以欢快的使用啦!
BeanCopierUtils.copyProperties(dto, vo);
到这里,大家发现,好像就封装了一个工具类,和原型模式并没有什么关系啊。
对象的 clone
到此其实在代码中都可以使用了,不过还是要在 DTO、VO 中声明 clone 方法,这样之后使用才会更方便~
/**
* 将当前对象转化为目标对象
*
* @param clazz
* @param
* @return
* @throws Exception
*/
public T clone(Class clazz) throws Exception {
T target = clazz.newInstance();
BeanCopierUtils.copyProperties(this, target);
return target;
}
现在使用的时候就可以
AccountVO accountVO = accountDTO.clone(AccountVO.class);
不过也是有弊端的,比如这里使用的是泛型,我明明是 UserVO 要 Clone , 你非得传一个 AddressDTO,那我也没得办法了。
至于进一步演化,可以将 clone 抽象到公共方法中,比如给所有 DTO 创建一个 BaseDTO。
还有深拷贝这块,也需要注意。
总结
其实工作中有很多设计模式,只不过用到了,大家没有发现。
当然工作中使用的时候,都是一切为了敏捷,可能并没有定义什么 Prototype 接口之类的,但是还是要多总结。
最后,小伙伴们工作中,有使用什么设计模式,以及实际中的应用场景,欢迎留言分享。