• 工作中的设计模式 —— 原型模式


    前言

    原型模式是一种创建型设计模式, 使你能够复制已有对象, 而又无需使代码依赖它们所属的类。

    通俗说法,就是将一个类作为原型,然后复制出来另一个类。

    使用场景

    这么一说,是不是发现我们经常使用?

    比如咱们项目中有 BO、DTO、VO,但是在开发过程中,需要各种转换,get/set,一般情况下大家都会使用 BeanUtils,将一个类的属性值 set 到另一个类的属性值中,然后返回。

    当然,也有一个实体直接从头捅到尾的。

    关于 BeanUtils 的 copy 方法,各个框架都提供了相关工具,不过 Java 开发手册 有指出 Apache BeanUtils 性能较差、也推荐了其他框架。

    Java 开发手册

    这里介绍的是使用 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<String, BeanCopier> 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 <T>
     * @return
     * @throws Exception
     */
    public <T> T clone(Class<T> 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 接口之类的,但是还是要多总结。

    最后,小伙伴们工作中,有使用什么设计模式,以及实际中的应用场景,欢迎留言分享。

    相关资料

    1. 《深入设计模式》:https://refactoringguru.cn/design-patterns
    2. 封面图:https://refactoringguru.cn/design-patterns/prototype

    作者: 刘志航

    公众号:『 程序员小航 』

    版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Notes

  • 相关阅读:
    BootStrap 智能表单系列 五 表单依赖插件处理
    BootStrap 智能表单系列 四 表单布局介绍
    BootStrap 智能表单系列 三 分块表单配置的介绍
    LinQ.OrderBy 多个字段排序
    ABP.NET CORE 遇到的小问题
    vs2017断点无效 当前不会命中断点 已设置断点单还未绑定
    DateTime 取年月日;字符串截取
    C# DateTime 多个时间段循环相加;两个时间段求差值
    ABP.Net Core 小白使用教程 附件:ABP.NET中文文档
    ASP.NET MVC+Easyui 后台管理系统的图片上传
  • 原文地址:https://www.cnblogs.com/liuzhihang/p/design-patterns-prototype.html
Copyright © 2020-2023  润新知