• 设计模式-原型模式


    一、定义

    (1)原型模式是指:原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。(有一个模板类的对象,通过拷贝这个对象获取一个一样的对象)。

    (2)调用者不需要知道创建对象的细节,不需要调用构造函数。

    (3)属于创建型模式。

    二、场景

    (1)类初始化过程中消耗资源多。

    (2)new产生的对象需要一个非常繁琐的过程(数据准备,访问权限)。

    (3)构造函数比较复杂。

    (4)在一个循环中生产大量对象时。

    比如下面这个场景(需要多次的get,set):

    这种场景我们可以怎么优化处理呢?

    (1)BeanUtils.copy();//原型模式

    (2)JSON.parseObject();//通用的方法,直接把值转成对象

    (3)Guava   Copy 工具类//原型工具类

    原型模式给我们带来的最大的方便就是简化产生对象的这个过程,不需要去通过构造函数构造

    三、浅克隆与深克隆

    Java中提供了一种类克隆的机制,在java的jdk中就可以实现一种原型模式:

    (1)浅克隆

    package com.songyan.prototype;
    
    /**
     * author:songyan
     * date: 2019/10/10
     **/
    public interface ProtoType {
        ProtoType clone();
    }
    package com.songyan.prototype;
    
    import java.util.List;
    
    /**
     * author:songyan
     * date: 2019/10/10
     **/
    public class ConcretePrototypeA implements ProtoType{
        private int age;
        private String name;
        private List hobbies;
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public List getHobbies() {
            return hobbies;
        }
    
        public void setHobbies(List hobbies) {
            this.hobbies = hobbies;
        }
    
        @Override
        public ProtoType clone() {
            ConcretePrototypeA concretePrototypeA = new ConcretePrototypeA();
            concretePrototypeA.setAge(this.age);
            concretePrototypeA.setName(this.name);
            concretePrototypeA.setHobbies(this.hobbies);
            return concretePrototypeA;
        }
    }
    package com.songyan.prototype;
    
    /**
     * author:songyan
     * date: 2019/10/10
     **/
    public class Client {
        public ProtoType startClone(ProtoType concretePrototype){
            ConcretePrototypeA concretePrototypeA = new ConcretePrototypeA();
            return concretePrototype.clone();
        }
    }
    package com.songyan.prototype;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * author:songyan
     * date: 2019/10/10
     **/
    public class PrototypeTest {
        public static void main(String[] args) {
            ConcretePrototypeA concretePrototypeA = new ConcretePrototypeA();
            concretePrototypeA.setAge(18);
            concretePrototypeA.setName("songyan");
            List hobbies = new ArrayList<Object>();
            concretePrototypeA.setHobbies(hobbies);
    
            Client  client = new Client();
            ConcretePrototypeA copy = (ConcretePrototypeA)client.startClone(concretePrototypeA);
            System.out.println(concretePrototypeA);
            System.out.println(copy);
            System.out.println(copy.getHobbies() == concretePrototypeA.getHobbies());
        }
    
    }

    这里会发现克隆出来的引用类型的对象,只是复制了原来的引用,指向了同一个对象,这样就会导致一个对象的值改变了,其他的克隆出来的对象的引用的值也会发生改变,这种克隆属于浅克隆。

    (2)深克隆

    在上面代码的基础上添加深克隆的代码:

    package com.songyan.prototype;
    
    /**
     * author:songyan
     * date: 2019/10/10
     **/
    public interface ProtoType {
        ProtoType clone();
        ProtoType deepClone();
    
    }
    package com.songyan.prototype;
    
    import java.io.*;
    import java.util.List;
    
    /**
     * author:songyan
     * date: 2019/10/10
     **/
    public class ConcretePrototypeA implements ProtoType,Serializable{
    
        private int age;
        private String name;
        private List hobbies;
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public List getHobbies() {
            return hobbies;
        }
    
        public void setHobbies(List hobbies) {
            this.hobbies = hobbies;
        }
    
        @Override
        public ProtoType clone() {
            ConcretePrototypeA concretePrototypeA = new ConcretePrototypeA();
            concretePrototypeA.setAge(this.age);
            concretePrototypeA.setName(this.name);
            concretePrototypeA.setHobbies(this.hobbies);
            return concretePrototypeA;
        }
    
        /**
         * 对象字节码的直接扩容
         * @return
         */
        @Override
        public ProtoType deepClone() {
            try {
                //在内存中操作
                //将字节码写入内存
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                ObjectOutputStream obs = new ObjectOutputStream(bos);
                obs.writeObject(this);
    
                //读取字节码,将字节码转成对象
                ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
                ObjectInputStream ois = new ObjectInputStream(bis);
                ConcretePrototypeA copy = (ConcretePrototypeA)ois.readObject();
                return copy;
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

    深克隆是直接克隆对象的字节码生成新的对象。

    四、可能出现的问题

    (1)问题:单例被破坏

    (2)解决:

      1)在clone方法中直接返回单例的对象

      2)不实现cloneable接口

      3)新增readResolve方法

  • 相关阅读:
    修改spring boot 的banner
    创建oracle 数据库的时候 提示 “使用database control配置数据库时,要求在当前oracle主目录中配置监听程序”
    Spring Boot 中文乱码解决
    SharePoint 2013 安装图解
    Hadoop 数据安全方案 Apache Eagle
    通用财经数据传输与监控平台1.0(泛型,接口与基类,Sql,Ibatis,Awt,Swing)
    应用Druid监控SQL语句的执行情况
    监控和剖析数据库操作 -- P6Spy、SQL Profiler、IronTrack SQL 使用简介
    Jboss7集群配置说明
    JavaMelody监控SQL
  • 原文地址:https://www.cnblogs.com/excellencesy/p/11648661.html
Copyright © 2020-2023  润新知