设计模式之原型模式:以自己为原型,自己实现自己的对象拷贝逻辑

场景

场景1:

(1) 如果一个对象,我们希望拷贝一个这个对象

(2) 就是弄出来这个类的另外一个实例,实例的属性跟之前的实例是一模一样的

场景2:

(1)电商项目中各种对象VO,DTO,DO数据转换就可以使用原型模式,将一个基础数据拷贝到另一个数据对象里面去。

(2)刚从DAO中查询出来的一个ProductDO,包含了10个字段,然后接着在service中处理完成之后,需要返回一个ProductDTO,包含20个字段,此时别使用new ProductDTO,set,set...;应该使用原型模式,将ProductDO里面的数据直接拷贝到ProductDTO中去。

场景3:

(1)仓储中心创建的采购入库单和采购单大部分字段是一样的,创建采购入库单的时候,获取到的是一个采购单,此时你可能需要将采购单数据拷贝一份到采购入库单中去。

内容

1. 不使用设计模式

1.1 类图
1.2 代码
复制代码
public class NonPattern2 {
    /**
     * 定义一个对象:里面有其他对象的引用,我们实现拷贝
     */
    public static void main(String[] args) {
        //1. 创建一个对象,进行拷贝
        Product product = new Product("汽车", new Component("汽车轮胎"));
        
        //2.手动来拷贝
        Product copyedProduct = new Product(product.getName(),product.getComponent());
        System.out.println("product:"+product);
        System.out.println("copyedProduct:"+copyedProduct);

        /**
         * 输出:
         * product:Product{name='汽车', component=Component{name='汽车轮胎'}}
         * copyedProduct:Product{name='汽车', component=Component{name='汽车轮胎'}}
         */
    }

    //===================产品实体类====================
    public static class Product{
        private String name;
        private Component component;
        public Product(String name,Component component){
             this.component =component;
             this.name = name;
        }

        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Component getComponent() {
            return component;
        }
        public void setComponent(Component component) {
            this.component = component;
        }

        @Override
        public String toString() {
            return "Product{" +
                    "name='" + name + '\'' +
                    ", component=" + component +
                    '}';
        }
    }

    public static class Component{
        private String name;
        public Component(String name){
               this.name = name;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "Component{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
}

2. 使用设计模式

  1. 这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
  2. 这里实现原型拷贝最主要的是对象里面的clone方法。
2.1 类图
2.2 代码
复制代码
public class PrototypePattern2 {
    public static void main(String[] args) {
        try {
            Product product = new Product("汽车", new Component("汽车轮胎"));
            Product copyedProduct = (Product) product.clone();
            System.out.println("product:"+product);
            System.out.println("copyedProduct:"+copyedProduct);
            /**
             * 输出:
             * product:Product{name='汽车', component=Component{name='汽车轮胎'}}
             * copyedProduct:Product{name='汽车', component=Component{name='汽车轮胎'}}
             */
        }catch (Exception e){
            e.printStackTrace();
        }
    }
//=====================产品类======================
     public static class Product{
       private String name;
       private Component component;
       public Product(String name,Component component){
           this.name = name;
           this.component = component;
       }

       @Override
       protected Object clone() throws CloneNotSupportedException {
        //浅拷贝,就是我们现在的一个实现 就是仅仅简单的对当前所有的变量进行一个拷贝
        // return new Product(getName(),getComponent());

        // 深考别,递归对自己引用的对象也进行拷贝
        return new Product(getName(),(Component) getComponent().clone());
       }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Component getComponent() {
            return component;
        }

        public void setComponent(Component component) {
            this.component = component;
        }

        @Override
        public String toString() {
            return "Product{" +
                    "name='" + name + '\'' +
                    ", component=" + component +
                    '}';
        }
}

    public static class Component{
      private String name;
      public Component(String name){
          this.name = name;
      }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return new Component(getName());
    }

     public String getName() {
        return name;
     }
     public void setName(String name) {
        this.name = name;
     }

    @Override
    public String toString() {
        return "Component{" +
                "name='" + name + '\'' +
                '}';
       }
   }
}

3.总结

3.1 不使用设计模式对比
  1. 代码的拷贝逻辑,是每个要拷贝的调用方(main方法)自己来实现的;相同的拷贝逻辑会分散在很多不同的地方,如果拷贝逻辑改变了,多个调用的地方都要修改代码。
  2. 可维护性、可扩展性,很差。
3.2 使用原型模式
  1. 原对象拷贝直接使用原对象的clone方法,是在目标对象自身,而不是调用方,调用方不用关注拷贝逻辑。
  2. 扩展性强:如果目标对象添加了新属性,拷贝逻辑可直接在目标对象的clone()修改。
相关推荐
丘山一郎8 小时前
Spring 中的IOC控制反转 和DI依赖注入
java·后端·spring
码视野8 小时前
基于 Spring Boot + Vue3 的【大学英语四六级 (CET-4/6) 作文智能评分与句式润色系统】设计与实现(含PRD/三端高保真源码/大屏)
java·前端·人工智能·spring boot·后端·vue3
MetaLite8 小时前
Spring-AOP自调用为什么失效-AopContext真能解决吗
java·后端·spring
大模型码小白8 小时前
AI 对话流性能调优:万级消息的虚拟滚动落地
java·大数据·前端·javascript·人工智能·算法·机器学习
许彰午8 小时前
14-字段级SM4加密与SM2签名
java·低代码·架构
许彰午10 小时前
13-describe元数据输出
java·低代码·架构·状态模式
用户37215742613511 小时前
Java 设置 Word 文档编辑限制并允许指定区域编辑
java
宠友信息11 小时前
社区类源码开发实践中的仿小红书系统技术要点分析
java·spring boot·redis·mysql·uni-app·vue·内容运营
用户37215742613511 小时前
Java 设置 PDF 表单域只读或扁平化
java
luteres13 小时前
Spring学习笔记
java·后端·spring