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

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

96 Mrsunup 关注

2018.09.02 12:38* 字数 807 阅读 48评论 0喜欢 0

原型模式就是从一个对象再创建另外一个可定制的对象, 而且不需要知道任何创建的细节。
所谓原型模式, 就是 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();
        }
    }
}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值