美文网首页
2020-07-23 原型模式

2020-07-23 原型模式

作者: 竹blue | 来源:发表于2020-08-05 02:45 被阅读0次

    原型模式

    原型模式通用写法

     是指通过拷贝原型实例来创建新的对象,具体来说是通过系统中已经存在的实例为原型,基于内存二进制流进行拷贝来创建新的对象;不调用构造函数。属于创建型模式。

      1. 因为是基于二进制流创建对象,相比基于构造函数创建对象,性能大大提高
      2. 可以通过来保存对象的中间状态,可用于数据的回滚操作。

     1. 需要类实现克隆方法。
     2. 克隆方法在类内部,对已有对象进行改造时违法开闭原则。
     3. 深度克隆需要编写较复杂的代码,如果当前对象存在多重嵌套,需要引用的类都支持深度克隆,实现比较麻烦,[注:可通过 JSON.parseObject(json,new TypeReference<Object>(){});
    来规避。
    ]

     1. 类初始化消耗资源较多,如创建数据连接。
     2. 通过构造函数创建对象过程比较繁琐,如权限访问。
     3. 构造函数比较复杂。
     4. 循环创建大量对象。

     JDK源码中的ArrayList.clone()方法通过原型模式实现,通过实现Cloneable接口的clone()方法来实现浅克隆。
    public class ArrayListextends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    {
    /**
         * 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);
            }
        }
    }
    

    浅clone

    \color{red}{定义:}
     只是完整复制了值类型的数据,没有给引用对象赋值,使得引用对象仍指向原来对象的地址。
    \color{red}{优点:}
      1. 规避了通过构造函数创建对象。
    \color{red}{缺点:}
     1. 如果实例中存在引用对象,当拷贝对象的引用成员变量被修改时,原的对象该引用也被修改了
    \color{red}{示例代码:}

    
    public class ConcretePrototype {
    
        private int age;
        private String name;
    
        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;
        }
    
        @Override
        public String toString() {
            return "ConcretePrototype{" +
                    "age=" + age +
                    ", name='" + name + '\'' +
                    '}';
        }
    }
    
    public class BeanUtils {
    
        public static Object copy(Object protorype) {
            Class clazz = protorype.getClass();
            Object returnValue = null;
            try {
                returnValue = clazz.newInstance();
                for (Field field : clazz.getDeclaredFields()) {
                    field.setAccessible(true);
                    field.set(returnValue, field.get(protorype));
                }
            }catch (Exception e){
                e.printStackTrace();
            }
            return returnValue;
        }
    }
    
    public class Client {
        public static void main(String[] args) {
    
            ConcretePrototype prototype = (ConcretePrototype)BeanUtils.copy(new ConcretePrototype());
            System.out.println(prototype);
        }
    }
    

    深clone

    \color{red}{定义:}
     通过JSON或者序列化的方式(如:二进制流方式)使得引用对象得以赋值,[注意深度clone破坏了单例模式,二者是不能共存的。]
    \color{red}{优点:}
     抽象工厂非常完美清晰地描述了产品族和产品等级结构之间的关系--即抽象工厂可以理解为工厂方法的集合。
    \color{red}{示例代码:}

    @Getter
    @Setter
    public class Person implements Serializable,Cloneable {
        /**
         * 年龄
         */
        private int age;
        /**
         * 姓名
         */
        private String name;
        /**
         * 爱好
         */
        private List hobbies;
    }
    
    
    @Setter
    @Getter
    public class Course implements Serializable {
        private String courseName;
    }
    @Getter
    @Setter
    public class Student extends Person {
    
        private Course course;
    
        private Timestamp birthday;
    
        /**
         * 深克隆
         *
         * @return
         */
        public Student deepClone(){
            try {
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                ObjectOutputStream outputStream = new ObjectOutputStream(bos);
                outputStream.writeObject(this);
    
                ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
                ObjectInputStream inputStream = new ObjectInputStream(bis);
    
                Student result = (Student)inputStream.readObject();
    
                return result;
            }catch (Exception e){
                System.out.println("Failed to deep clone, reason is "+ e.getMessage());
                return null;
            }
        }
    }
    
    public class DeepCloneTest {
        public static void main(String[] args) {
            Student student = new Student();
            student.setName("小明");
            List<String> hobbies = new ArrayList<String>(1);
            hobbies.add("game");
            student.setHobbies(hobbies);
            student.setAge(10);
            student.setCourse(new Course());
            student.setBirthday(new Timestamp(System.currentTimeMillis()));
    
    
            Student deepClone = student.deepClone();
            System.err.println("深克隆:" + student.getCourse().equals(deepClone.getCourse()));
    }
    
    

    浅clone和深clone的区别

     1. 实现Cloneable接口的都是浅clone
     2. 通过序列化或转Json可实现深clone。

    原型模式和单例模式的区别

    原型模式的实例是不同的,单例模式创建出来的对象实例是相同的。

    总结

     原型模式的核心是通过原型实例拷贝得到新的实例对象,适用于对象创建较为复杂的场景如构造函数较复杂(成员变量数量较大的情况),深度克隆相对浅克隆解决了引用对象赋值问题,但是增加了代码编写难度和内存占用(主要是因为破坏了单例模式)

    相关文章

      网友评论

          本文标题:2020-07-23 原型模式

          本文链接:https://www.haomeiwen.com/subject/zzoxlktx.html