zoukankan      html  css  js  c++  java
  • JAVA 设计模式之 原型模式详解

    原型模式(Prototype Pattern)是指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

    原型模式利用的是克隆的原理,创建新的对象,JDK提供的Cloneable 和JSON、springUtil里面的克隆都是一般浅克隆,与之对应的还有深克隆

    1、浅克隆

      浅克隆也是穿件一个新的对象,不过该对象的属性值是被克隆对象的,如果修改被克隆对象,后者跟着修改。

    下面我们用Cloneable写一个简单的浅克隆

    import java.util.List;
    /**
     * @Description TODO
     * @Author Bert
     * @Date 2019610 0010
     */
    public class ShallowClone implements Cloneable{
    
        private String name;
        private int age;
        private List<String> hobbies;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public List<String> getHobbies() {
            return hobbies;
        }
    
        public void setHobbies(List<String> hobbies) {
            this.hobbies = hobbies;
        }
    
        //实现 Cloneable 的 clone 方法  属于浅克隆
        @Override
        public ShallowClone clone() {
            ShallowClone shallowClone = null;
            try {
                shallowClone = (ShallowClone)super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return shallowClone;
        }
    
        //手写 浅克隆 方法
        public ShallowClone spellClone(){
            ShallowClone shallowClone = new ShallowClone();
            shallowClone.setName(this.name);
            shallowClone.setAge(this.age);
            shallowClone.setHobbies(this.hobbies);
            return shallowClone;
        }
    }
    

      测试代码:

    public static void main(String[] args) {
    
            ShallowClone shallowClone = new ShallowClone();
            shallowClone.setName("ZhangSan");
            shallowClone.setAge(21);
            List<String> list = new ArrayList<>();
            list.add("play game");
            list.add("Listen music");
            shallowClone.setHobbies(list);
            
            //调用Cloneable 的clone方法
            ShallowClone clone1 = shallowClone.clone();
            //添加喜好
            shallowClone.getHobbies().add("fitness");
            //调用手写的浅克隆方法
            ShallowClone clone2 = shallowClone.spellClone();
    
            System.out.println(shallowClone == clone1);//判读是否为同一个对象
            System.out.println(shallowClone == clone2);//判读是否为同一个对象
    
            System.out.println("克隆对象中引用类型地址:"+shallowClone.getHobbies());
            System.out.println("克隆对象中引用类型地址:"+clone1.getHobbies());
            System.out.println("克隆对象中引用类型地址:"+clone2.getHobbies());
        }
    

      运行结果:

    false
    false
    克隆对象中引用类型地址:[play game, Listen music, fitness]
    克隆对象中引用类型地址:[play game, Listen music, fitness]
    克隆对象中引用类型地址:[play game, Listen music, fitness]

      从运行结果我们可以看出,克隆对象和原来的对象不是同一个,但对象的属性完全一样,即使改变了其中一个,其他的也会跟着改变。

      通过上面spellClone() 方法我们可以看出,浅克隆的整个过程就是,创建一个新的对象,然后新对象的每个值都是由原对象的值,通过 = 进行赋值;

        (1)拷贝后获取的是一个独立的对象,和原对象拥有不同的内存地址;

        (2)基本元素类型,两者是隔离的,int, Integer, long, Long, char, Charset, byte,Byte, boolean, Boolean, float,Float, double, Double, String

        (3)非基本数据类型(如基本容器,其他对象等),只是拷贝了一份引用出去了,实际指向的依然是同一份,例如上的list<String>

      一句话总结就是:基本数据类型是值赋值;非基本的就是引用赋值。

    2、深克隆

      创建一个全新的对象,新的对象内部所有的成员也都是全新的,只是初始化的值已经由被克隆的对象确定,但是他们是两个完全独立的对象,修改是隔离,互不影响。

    下面我们来写一个简单的深克隆

    import java.io.*;
    import java.util.ArrayList;
    import java.util.List;
    /**
     * @Description TODO
     * @Author Bert
     * @Date 2019610 0010
     */
    public class DeepClone implements Serializable{
        private String name;
        private int age;
        private List<String> hobbies;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public List<String> getHobbies() {
            return hobbies;
        }
    
        public void setHobbies(List<String> hobbies) {
            this.hobbies = hobbies;
        }
    
        // 深克隆 方法 1
        public DeepClone deepClone(){
            DeepClone deepClone = new DeepClone();
            deepClone.setName(this.name);
            deepClone.setAge(this.age);
            //基本数据类型 重新创建
            if(null != this.hobbies){
                deepClone.setHobbies(new ArrayList<>(this.hobbies));
            }
            return deepClone;
        }
    
        //深克隆 2 通过 byte字节码 ,这种方式需要 实现 Serializable
        public DeepClone deepCloneByte() {
            DeepClone dClone = null;
            ByteArrayOutputStream bys = new ByteArrayOutputStream();
            try {
                ObjectOutputStream oos = new ObjectOutputStream(bys);
                oos.writeObject(this);
    
                ByteArrayInputStream bis = new ByteArrayInputStream(bys.toByteArray());
                ObjectInputStream ois = new ObjectInputStream(bis);
                dClone = (DeepClone)ois.readObject();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return dClone;
        }
    
    }
    

      测试代码:

    public static void main(String[] args) {
            DeepClone deepClone = new DeepClone();
            deepClone.setName("ZhangSan");
            deepClone.setAge(21);
            List<String> list = new ArrayList<>();
            list.add("play game");
            list.add("Listen music");
            deepClone.setHobbies(list);
            //调用第一种方式,并修改值
            DeepClone deepClone1 = deepClone.deepClone();
            deepClone1.getHobbies().add("fitness");
            deepClone1.setAge(22);
            //调用第二种方式,并修改值
            DeepClone deepClone2 = deepClone.deepCloneByte();
            deepClone2.getHobbies().add("Climbing mountain");
    
            System.out.println(deepClone == deepClone1);
            System.out.println(deepClone == deepClone2);
            System.out.println("克隆对象中引用类型地址:"+deepClone.getHobbies());
            System.out.println("克隆对象中引用类型地址:"+deepClone1.getHobbies());
            System.out.println("克隆对象中引用类型地址:"+deepClone2.getHobbies());
        }
    

      运行结果:

    false
    false
    克隆对象中引用类型地址:[play game, Listen music]
    克隆对象中引用类型地址:[play game, Listen music, fitness]
    克隆对象中引用类型地址:[play game, Listen music, Climbing mountain]
    

      以上可以看出深克隆的对象之间修改完全不受影响。

    3、原型模式运用场景

      (1)类初始化消耗资源较多。

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

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

      (4)循环体中生产大量对象时。

    在 Spring 中,原型模式应用得非常广泛。例如 scope=“prototype”,在我们经常用 的 JSON.parseObject()也是一种原型模式。

    4、解决深克隆破坏单例模式

      如果我们的被克隆对象是单例模式,深克隆就得破坏单例模式。

      解决方案:禁止深克隆。一是不实现Cloneable; 二是实现Cloneable ,在clone方法中返回我们的单例。

     @Override
        protected Object clone() throws CloneNotSupportedException {
            return INSTANCE;
        }
    

      Cloneable 源码分析:

      以ArryList 为例,ArrayList 就实现了 Cloneable 接口

    /**
         * Returns a shallow copy of this <tt>ArrayList</tt> instance.  (The
         * elements themselves are not copied.)
         *
         * @return a clone of this <tt>ArrayList</tt> instance
         */
        public Object clone() {
            try {
                ArrayList<?> v = (ArrayList<?>) super.clone();
                v.elementData = Arrays.copyOf(elementData, size);
                v.modCount = 0;
                return v;
            } catch (CloneNotSupportedException e) {
                // this shouldn't happen, since we are Cloneable
                throw new InternalError(e);
            }
        }
    

      

  • 相关阅读:
    FreeSWITCH一些需求应对
    CentOS 7安装Mysql并设置开机自启动
    RTP学习笔记
    SDP学习笔记
    Quartz实用二三事
    Quartz:ERROR threw an unhandled Exception
    CentOS 7一些常用配置
    Java获取音频文件(MP3)的播放时长
    使用Callable和Future接口创建线程
    join() 方法详解及应用场景
  • 原文地址:https://www.cnblogs.com/bert227/p/11000743.html
Copyright © 2011-2022 走看看