• 设计模式4---原型模式(Prototype Pattern)


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


    原型模式结构图

    通俗来说:原型模式就是深拷贝和浅拷贝的实现。

    浅拷贝

    只实现了值拷贝,对于引用对象还是指向原来的对象。

    • 父类实现clone方法,子类没有实现clone方法,其效果是浅拷贝。
    • 父类实现clone方法,子类也实现clone方法,本来我想应该是深拷贝了,没想到也是浅拷贝
    package com.prototype;
    import java.io.Serializable;
    
    public class Work implements Serializable,Cloneable{
        private static final long serialVersionUID = 207835812839542204L;
        private String job;
        private double salary;
        public Work(String job,double salary) {
            this.job = job;
            this.salary = salary;
        }
        @Override
        public String toString() {
            return "Work [job=" + job + ", salary=" + salary + "]";
        }
        public String getJob() {
            return job;
        }
        public void setJob(String job) {
            this.job = job;
        }
        public double getSalary() {
            return salary;
        }
        public void setSalary(double salary) {
            this.salary = salary;
        }
    }
    package com.prototype;
    
    import java.io.Serializable;
    
    public class User implements Serializable,Cloneable{
        private static final long serialVersionUID = -2260332138558500447L;
    
        private String name = "";
        private Work work = null;
    
        public User(String name,String job,double salary) {
            this.name=name;
            work = new Work(job, salary);
        }
    
        public void changeJob(String job){
            this.work.setJob(job);
        }
        /*只需要实现Cloneable接口,覆写clone方法,此处clone方法可以改成任意的名称,
        因为Cloneable接口是个空接口,你可以任意定义实现类的方法名,如cloneA或者cloneB。
        重点是super.clone()这句话,super.clone()调用的是Object的clone()方法,而在Object类中,clone()是native的。
        */
        //浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    
        @Override
        public String toString() {
            return "User [name=" + name + ", work=" + work + "]";
        }
    
    }
    package com.prototype;
    
    public class Main {
    
        public static void main(String[] args) {
            try {
                User user1 = new User("zhangsan","ceo",100000);
                User user2 = (User) user1.clone();
                System.out.println(user1);
                System.out.println(user2);
                System.out.println("修改job");
                user2.changeJob("cfo");
                System.out.println(user1);
                System.out.println(user2);
    
    
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
        }
    }
    //结果
    User [name=zhangsan, work=Work [job=ceo, salary=100000.0]]
    User [name=zhangsan, work=Work [job=ceo, salary=100000.0]]
    修改job
    User [name=zhangsan, work=Work [job=cfo, salary=100000.0]]
    User [name=zhangsan, work=Work [job=cfo, salary=100000.0]]

    深拷贝

    即实现了值拷贝,也实现了对引用对象的拷贝。

    • 法一
        //深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。
        //实现深复制,需要采用流的形式读入当前对象的二进制输入,再写出二进制数据对应的对象。
        public Object deepClone() throws IOException, ClassNotFoundException{
            //写入当前对象的二进制流
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);
    
            //读入二进制流产生的新对象
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            return ois.readObject();
        }
    • 法二
        //将User的拷贝方法修改为下面的方法。
        @Override
        protected Object clone() throws CloneNotSupportedException {
            Work w = (Work) work.clone();//对其引用变量进行拷贝
            User u = (User)super.clone();//自身拷贝
            u.work = w;//引用变量重新赋值。
            return u;
        }



    ===================================================
    • 定义

      用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。

    • 使用场景

      原型模式被用在频繁调用且极其相似的对象上,它会克隆对象并设置改变后的属性,而且消耗的资源较少。

    • 代码举例实现

    ProtoTypeImpl.java

     package com.design.prototype;
    
    public class ProtoTypeImpl implements Cloneable{
    
        private int shallowClone;
    
        private DeepClone deepClone = new DeepClone();
    
        public ProtoTypeImpl() {
            System.out.println("construct is called");
        }
    
        public void print() {
            // TODO Auto-generated method stub
            System.out.println(shallowClone);
            System.out.println(deepClone.getS());
        }
    
    
        @Override
        protected ProtoTypeImpl clone(){
            // TODO Auto-generated method stub
            try{
                ProtoTypeImpl protoTypeImp =  (ProtoTypeImpl) super.clone();
                //protoTypeImp.shallowClone = this.shallowClone;
                //protoTypeImp.deepClone = this.deepClone.clone();
                return protoTypeImp;
            }catch(Exception e){
                e.printStackTrace();
                return null;
            }
    
        }
    
    
        public void setShallowClone(int shallowClone) {
            this.shallowClone = shallowClone;
        }
    
        public void setS(String s){
            deepClone.setS(s);
        }
    }

    DeepClone.java

    package com.design.prototype;
    
    public class DeepClone implements Cloneable{
        private String s;
    
        public String getS() {
            return s;
        }
    
        public void setS(String s) {
            this.s = s;
        }
    
        @Override
        protected DeepClone clone(){
            // TODO Auto-generated method stub
            try {
                return (DeepClone)super.clone();
            } catch (CloneNotSupportedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return null;
        }
    }

    App.java

    package com.design.prototype;
    
    public class App {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            ProtoTypeImpl protoTypeImp = new ProtoTypeImpl();
            protoTypeImp.setShallowClone(1);
            protoTypeImp.setS("deep clone");
            protoTypeImp.print();
            System.out.println("-------------");
            ProtoTypeImpl protoTypeImp2 = protoTypeImp.clone();
            protoTypeImp2.setShallowClone(2);
            protoTypeImp2.setS("deep clone 2");
    
            protoTypeImp2.print();
            System.out.println("-------------");
            protoTypeImp.print();
        }
    
    }
    • 结果分析

    运行结果1.png
    运行结果1.png
    1. 这个现象主要是由于深浅复制引起的,普通类型的数据没有问题,而对象类型则有问题。同时我们应该注意到clone的时候构造函数是不会被调用的。

    2. 去掉ProtoTypeImpl.clone的两行注释(第一行没什么所谓,但是还是加上,有个对比)

      运行结果2.png
      运行结果2.png
    3. 总结优缺点

      • 优点
        原型模式是在内存二进制流的拷贝,要比直接 new 一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其点。
      • 缺点
        使用过程中要切记构造函数不会被调用,所以在构造函数完成的操作应该多加处理,还有深浅复制的问题



  • 相关阅读:
    APP_DEBUG作用
    tp字段映射机制原理
    unix、windows、mac 的换行习惯
    DroidCam 一片 红色 解决办法
    A3 A8 算法,中文简明解释
    /usr/local/mysql/bin/mysql P 3307 protocol=tcp 无法连接mysql
    [转载]网络基础:精解传输层安全协议
    无线网络加密一点漫谈
    安全模式:J2EE、Web服务和身份管理最佳实践与策略
    scp和winscp
  • 原文地址:https://www.cnblogs.com/linghu-java/p/5692563.html
Copyright © 2020-2023  润新知