(4)spring常用模式--------原型模式

原型模式就是从一个对象再创建另外一个可定制的对象, 而且不需要知道任何创建的细节。
所谓原型模式, 就是 Java 中的克隆技术, 以某个对象为原型。 复制出新的对象。 显然新的对象具备原型对象的特点, 效率高(避免了重新执行构造过程步骤)

在介绍原型模式之前,需要介绍浅拷贝和深拷贝的概念

1.浅拷贝和深拷贝的特点

浅拷贝

  • ①对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。
  • ②对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。

深拷贝:

  • ①复制对象的所有基本数据类型的成员变量值
  • ②为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象图进行拷贝!

总结
深拷贝对引用数据类型的成员变量的对象图中所有的对象都开辟了内存空间;而浅拷贝只是传递地址指向,新的对象并没有对引用数据类型创建内存空间

2.原型模式的浅拷贝和深拷贝的实现方式

  • 浅拷贝
     通过拷贝构造方法实现浅拷贝
     通过重写clone()方法进行浅拷贝
  • 深拷贝
     通过重写clone方法来实现深拷贝
     通过对象序列化实现深拷贝

接下来直接介绍浅拷贝和深拷贝的具体实现

在此之前,先给出原型模式的uml图


原型模式.png

3.原型模式的浅拷贝

浅度克隆目标的引用对象

/**
 * @Project: spring
 * @description:  浅度克隆目标的引用对象
 * @author: sunkang
 * @create: 2018-09-02 10:48
 * @ModificationHistory who      when       What
 **/
public class CloneableTarget   {

    public  String cloneName;

    public String cloneClass;
    
    public CloneableTarget( String cloneName,String cloneClass) {
        this.cloneName = cloneName;
        this.cloneClass = cloneClass;
    }
}

浅度克隆的对象的两种实现方式

/**
 * @Project: spring
 * @description:  克隆对象的浅拷贝
 *   1.通过构造方法来实现浅度拷贝
 *   2.通过clone()方法来实现浅度拷贝
 * @author: sunkang
 * @create: 2018-09-02 10:47
 * @ModificationHistory who      when       What
 **/
public class Prototype implements  Cloneable {

    public String name ;

    //拷贝的引用类型的成员变量
    public  CloneableTarget cloneableTarget;

    public Prototype(){

    }
    //1.通过构造方法来实现浅度拷贝
    public Prototype(Prototype prototype) {
        this.name = prototype.name;
        this.cloneableTarget = prototype.cloneableTarget;
    }
    //2.通过clone()方法来实现浅度拷贝
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

浅克隆的测试

/**
 * @Project: spring
 * @description: 浅度克隆对象的测试
 *
 * @author: sunkang
 * @create: 2018-09-02 10:51
 * @ModificationHistory who      when       What
 **/
public class CloneTest  {
    public static void main(String[] args) {
        Prototype  p = new Prototype();
        p.name="kang";
        p.cloneableTarget = new CloneableTarget("clone","CloneableTarget");
        System.out.println("原有的对象:"+p);
        System.out.println("原有的值对象引用:"+p.name.hashCode());
        System.out.println("原有的引用类型对象:"+p.cloneableTarget);
        try {
            //方式一 :通过重写clone()方法进行浅拷贝
            Prototype clonePrototype = (Prototype) p.clone();
            System.out.println("重写clone()克隆的对象:"+clonePrototype);
            System.out.println("重写clone()克隆的值对象引用:"+p.name.hashCode());
            System.out.println("重写clone()克隆的引用类型对象:"+ clonePrototype.cloneableTarget);

            //通过修改引用对象String类型的值,发现原有的对象的值没有发生改变,因为String对象是不可变对象,放在常量池中的,无法修改的
            //String 可以比较特殊,可以看做是值传递
            clonePrototype.name ="sun";
            System.out.println("原有对象的name:"+p.name);
            System.out.println("修改过的clone对象的name:"+clonePrototype.name);

            //方式二: 通过拷贝构造方法实现浅拷贝
            Prototype  constructClone=   new Prototype(p);
            System.out.println("构造方法克隆的对象:"+constructClone);
            System.out.println("构造方法克隆的值对象引用:"+constructClone.name.hashCode());
            System.out.println("构造方法克隆的引用类型对象:"+ constructClone.cloneableTarget);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

测试结果 : 可以发现引用类型的目标对象为同一个引用,string 对象可以看做是值传递,string对象是不可变的,克隆对象修改后的值对原有对象的值没有影响

浅克隆测试结果.png

4.原型模式的深拷贝

深度拷贝的目标引用对象

/**
 * 深度拷贝的目标引用对象
 */
public class DeepCloneableTarget implements Serializable,Cloneable {

    private  String cloneName;

    private String cloneClass;


    public DeepCloneableTarget(String cloneName, String cloneClass) {
        this.cloneName = cloneName;
        this.cloneClass = cloneClass;
    }

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

深度拷贝的实现拷贝的两种方式

/**
 * @Project: spring
 * @description: 深度拷贝的实现拷贝的两种方式
 * @author: sunkang
 * @create: 2018-09-02 11:19
 * @ModificationHistory who      when       What
 **/
public class DeepPrototype implements Serializable,Cloneable {

    public String name ;

    public  DeepCloneableTarget deepCloneableTarget;

    public DeepPrototype(){

    }
    //方式1 :通过重写clone方法来实现深拷贝  (引用对象多,这种方法比较繁琐)
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object deep = null;
        try {
            deep = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        DeepPrototype  deepPrototype = (DeepPrototype) deep;
        deepPrototype.deepCloneableTarget = (DeepCloneableTarget) deepPrototype.deepCloneableTarget.clone();
        return deepPrototype;
    }

    //方式2: 通过对象序列化实现深拷贝 (推荐)
    public Object deepClone(){
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        try {
             bos = new ByteArrayOutputStream();
             oos = new ObjectOutputStream(bos);
             oos.writeObject(this);

            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            return  ois.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            if(oos !=null){
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(bos !=null){
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            //输入流关闭省略
        }
        return null;
    }
}

深度拷贝的测试

/**
 * @Project: spring
 * @description:  深度拷贝的测试
 * @author: sunkang
 * @create: 2018-09-02 11:38
 * @ModificationHistory who      when       What
 **/
public class DeepCloneTest {

    public static void main(String[] args) {
        DeepPrototype p = new DeepPrototype();
        p.name="kang";

        p.deepCloneableTarget = new DeepCloneableTarget("clone","CloneableTarget");
        System.out.println("原有的对象:"+p);
        System.out.println("原有的值对象引用:"+p.name.hashCode());
        System.out.println("原有的引用类型对象:"+p.deepCloneableTarget);

        try {
            //方式一 :通过重写clone()方法进行浅拷贝
            DeepPrototype clonePrototype = (DeepPrototype) p.clone();
            System.out.println("clone()方法克隆的对象:"+clonePrototype);
            System.out.println("clone()方法克隆的值对象引用:"+p.name.hashCode());
            System.out.println("clone()方法克隆的引用类型对象:"+ clonePrototype.deepCloneableTarget);

            //方式二:  通过对象序列化实现深拷贝
            DeepPrototype  serializableClone= (DeepPrototype) p.deepClone();
            System.out.println("序列化方法克隆的对象:"+serializableClone);
            System.out.println("构序列化方法克隆的值对象引用:"+serializableClone.name.hashCode());
            System.out.println("序列化方法克隆的引用类型对象:"+ serializableClone.deepCloneableTarget);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

测试结果 :可以发现引用类型的成员变量的地址都是不一样的了,说明实现了深度拷贝

深拷贝的测试结果.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,110评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,443评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,474评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,881评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,902评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,698评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,418评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,332评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,796评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,968评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,110评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,792评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,455评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,003评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,130评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,348评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,047评论 2 355