深度揭秘原型(深浅克隆)模式!

本文详细介绍了原型模式的概念及应用场景,通过对比浅克隆和深克隆的区别,展示了如何实现深克隆的不同方法,并探讨了在何种情况下选择原型模式进行对象创建更为高效。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原型模式:
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

深克隆和浅克隆:
1、对于浅克隆

public class People implements Cloneable {
    String name;
    int age;
    Date date;
    public Date getDate() {
        return date;
    }
    public void setDate(Date date) {
        this.date = date;
    }
    public People(String name, int age, Date date) {
        super();
        this.name = name;
        this.age = age;
        this.date = date;
    }
    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;
    }

    @Override
    public String toString() {
        return "People [name=" + name + ", age=" + age + ", date=" + date + "]";
    }
    public People() {
        super();
    }

    public People(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {

        return super.clone();
    }

}

测试类:

public class Client {
    public static void main(String[] args) throws Exception {
        Date date = new Date(2364262352L);
        System.out.println(date);
        People p1 = new People("张三", 18,date);
        date.setTime(62786892498243L);
        System.out.println(date);
        People p2 = (People) p1.clone();

        System.out.println(p1);
        System.out.println(p2);
        System.out.println(p1.hashCode() +"-----"+p2.hashCode());
        /*
         * 打印结果:
         * 
         * People [name=张三, age=18, date=Sat Aug 22 11:28:18 GMT+08:00 3959]
         * People [name=张三, age=18, date=Sat Aug 22 11:28:18 GMT+08:00 3959]
         *发现:克隆之后在修改时间依然还是没有变化。
         * */
    }
}

对于浅克隆,如图所示:
这里写图片描述

深克隆:
这里有两种方式:
1、通过重写clone方法,来实现深克隆。

/**
 * 深度克隆
 * */
public class People2 implements Cloneable {
    String name;
    int age;
    Date date;
    public Date getDate() {
        return date;
    }
    public void setDate(Date date) {
        this.date = date;
    }
    public People2(String name, int age, Date date) {
        super();
        this.name = name;
        this.age = age;
        this.date = date;
    }
    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;
    }

    @Override
    public String toString() {
        return "People [name=" + name + ", age=" + age + ", date=" + date + "]";
    }
    public People2() {
        super();
    }

    public People2(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    @Override
    protected People2 clone() throws CloneNotSupportedException {
        //在克隆对象的同时把对象的属性也给克隆了
        Object obj = super.clone();
        People2 p = (People2) obj;
        Date d = (Date) p.date.clone();
        p.setDate(d);
        return p;
    }

}

测试代码:

public class Client2 {

    public static void main(String[] args) throws CloneNotSupportedException {
        Date date = new Date(2678264781672L);
        People2 p = new People2("张三",12,date);
        People2 p1 = p.clone();
        date.setTime(897892798732L);
        System.out.println(p);
        System.out.println(p1);
        /*
         * 打印结果:
         * People [name=张三, age=12, date=Mon Jun 15 14:39:58 GMT+08:00 1998]
         *  People [name=张三, age=12, date=Sat Nov 14 18:26:21 GMT+08:00 2054]
         * 可以观察到深度克隆之后,在修改属性此时就会发生变化
         * */

    }
}

第二种方式,通过序列化和反序列化来实现:

public class People3 implements Serializable {

    private static final long serialVersionUID = 1L;



    String name;
    Date date;
    @Override
    public String toString() {
        return "People3 [name=" + name + ", date=" + date + "]";
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Date getDate() {
        return date;
    }
    public void setDate(Date date) {
        this.date = date;
    }
    public People3(String name, Date date) {
        super();
        this.name = name;
        this.date = date;
    }
    public People3() {
        super();
        // TODO Auto-generated constructor stub
    }

    //内容写到数组里边然后在读取 , 通过此种方式来深度复制对象
    public People3 clone(People3 p){
        //定义这个数组用于接收对象信息
        byte[] by=null;
        //初始化字节数组输出流
        ByteArrayOutputStream baos = null;
        //初始化对象输出流
        ObjectOutputStream oos = null;
        try {
            baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            //将对象写入到硬盘中
            oos.writeObject(p);
            by = baos.toByteArray();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            try {
                if (oos != null) {
                    oos.close();
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
        //获取字节数组输入流
        ByteArrayInputStream bais = null;
        //获得对象输入六
        ObjectInputStream ois = null;
        try {
            //读取by数组
            bais = new ByteArrayInputStream(by);

            ois = new ObjectInputStream(bais);
            //通过反序列化读取到对象
            People3 p1= (People3) ois.readObject();
            //System.out.println(p);
            return p1;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            try {
                bais.close();
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            try {
                if (ois != null) {
                    ois.close();
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return null;
    }
}

测试代码:

public class Client3 {
    public static void main(String[] args) {
        Date d = new Date(35483782375L);
        System.out.println(d);
        People3 p = new People3("张三",d);
        People3 p1 = p.clone(p);
        d.setTime(78946582782L);
        System.out.println("p的时间"+"---"+d);
        System.out.println("p"+"---"+p);
        System.out.println("p1"+"---"+p1);
        /*
         * 打印结果:
         *  Tue Feb 16 00:36:22 GMT+08:00 1971
         *  p的时间---Mon Jul 03 01:36:22 GMT+08:00 1972
         *  p---People3 [name=张三, date=Mon Jul 03 01:36:22 GMT+08:00 1972]
         *  p1---People3 [name=张三, date=Tue Feb 16 00:36:22 GMT+08:00 1971]
         *
         * 如上一种深克隆一样
         * */

    }
}

那么,原型模式到底在什么时候用?
假设一个系统的产品类是动态加载的,而且产品类具有一定的等级结构。这个时候如果采取工厂模式的话,工厂类就不得不具有一个相应的等级结构。而产品品类的等级结构一旦变化,工厂类的等级结构就不得不有以恶相应的变化。这对于产品结构可能会有经常变化的系统来说,采用工厂模式就有不方便之处。
此时若采用原型模式,给每一个产品类配备一个克隆方法(大多时候只需个产品类等级结构配备一个根类配备一个克隆方法),便可免去工厂模式所带来的据哟有固定等级结构的工厂类。

还有一点,假设通过普通方法创建对象很耗时时,也可采用原型模式,例如:

/**
 * 测试普通new方式创建对象和clone方式创建对象的效率差异!
 * 如果需要短时间创建大量对象,并且new的过程比较耗时。则可以考虑使用原型模式!
 * 
 *
 */
public class Client4 {

    public static void testNew(int size){
        long start = System.currentTimeMillis();
        for(int i=0;i<size;i++){
            Laptop t = new Laptop();
        }
        long end = System.currentTimeMillis();
        System.out.println("new的方式创建耗时:"+(end-start));
    }

    public static void testClone(int size) throws CloneNotSupportedException{
        long start = System.currentTimeMillis();
        Laptop t = new Laptop();
        for(int i=0;i<size;i++){
            Laptop temp = (Laptop) t.clone();
        }
        long end = System.currentTimeMillis();
        System.out.println("clone的方式创建耗时:"+(end-start));
    }


    public static void main(String[] args) throws Exception {   
        testNew(1000);
        testClone(1000);
        /**
         * 测试结果:
         * new的方式创建耗时:10288
         *  clone的方式创建耗时:10
         *
         * 
         * */
    }
}


class Laptop implements Cloneable {  //笔记本电脑
    public Laptop() {
        try {
            Thread.sleep(10);  //模拟创建对象耗时的过程!
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object obj = super.clone();  //直接调用object对象的clone()方法!
        return obj;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Anguser

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值