java设计模式之原型模式

Prototype原型模式是一种创建型设计模式,Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。—百度百科。
原型模式又称为克隆模式,可以分为浅克隆和深克隆,下面分别用代码来实现这两种不同类型的克隆方式。
浅克隆:

package cn.zzit.prototype;

import java.util.Date;

public class Sheep implements Cloneable {
    private String name;
    private Date birthday;

    public Sheep(String name, Date birthday) {
        super();
        this.name = name;
        this.birthday = birthday;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

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

}

测试代码:

package cn.zzit.prototype;

import java.util.Date;
/**
 * 测试浅复制
 * @author yufu
 *
 */
public class Client {

    public static void main(String[] args) throws Exception {
        Date date=new Date(12366521155L);
        Sheep s1=new Sheep("多利羊",date);
        Sheep s2=(Sheep) s1.clone();
        System.out.println("s1对象:"+s1);
        System.out.println("s1对象的名字:"+s1.getName());
        System.out.println("s1对象的生日:"+s1.getBirthday());

        System.out.println("克隆的s2对象:"+s2);
        System.out.println("克隆的s2对象:"+s2.getName());
        System.out.println("克隆的s2对象:"+s2.getBirthday());
    }

}

输出结果:

s1对象:cn.zzit.prototype.Sheep@15db9742
s1对象的名字:多利羊
s1对象的生日:Sun May 24 11:08:41 CST 1970
克隆的s2对象:cn.zzit.prototype.Sheep@5c647e05
克隆的s2对象:多利羊
克隆的s2对象:Sun May 24 11:08:41 CST 1970

由输出结果我们可以看出,s1和s2虽然是不同的对象,但是他们的属性值是一样的,这样也就实现了s1对象的克隆。
深克隆,深克隆有两种实现方式
实现方式一:重写clone()方法,在方法内对属性进行克隆

package cn.zzit.prototype;

import java.util.Date;

public class Sheep2 implements Cloneable {
    private String name;
    private Date birthday;

    public Sheep2(String name, Date birthday) {
        super();
        this.name = name;
        this.birthday = birthday;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        // 深复制,复制了对象最初的值,如果对最初的值做了修改,则不会影响复制对象
        Object obj = super.clone();
        Sheep2 s2 = (Sheep2) obj;
        s2.birthday = (Date) this.birthday.clone();
        return obj;
    }

}

测试代码:

package cn.zzit.prototype;

import java.util.Date;
/**
 * 测试深复制
 * @author yufu
 *
 */
public class Client2 {

    public static void main(String[] args) throws Exception {
        Date date=new Date(12366521155L);
        Sheep2 s1=new Sheep2("多利羊",date);
        Sheep2 s2=(Sheep2) s1.clone();
        System.out.println("s1对象:"+s1);
        System.out.println("s1对象的名字:"+s1.getName());
        System.out.println("s1对象的生日:"+s1.getBirthday());
        date.setTime(55521452236L);
        System.out.println("修改s1对象的生日:"+s1.getBirthday());

        System.out.println("克隆的s2对象:"+s2);
        System.out.println("克隆的s2对象:"+s2.getName());
        System.out.println("克隆的s2对象:"+s2.getBirthday());
    }

}

输出结果:

s1对象:cn.zzit.prototype.Sheep2@15db9742
s1对象的名字:多利羊
s1对象的生日:Sun May 24 11:08:41 CST 1970
修改s1对象的生日:Tue Oct 05 22:37:32 CST 1971
克隆的s2对象:cn.zzit.prototype.Sheep2@5c647e05
克隆的s2对象:多利羊
克隆的s2对象:Sun May 24 11:08:41 CST 1970

由输出结果可以看出:虽然s1对象的生日属性值已经修改但是,克隆的得到的对象s2仍然是s1修改以前的值。
实现方式二:使用序列化和反序列化,需要克隆对象实现序列化接口

package cn.zzit.prototype;

import java.io.Serializable;
import java.util.Date;

public class Sheep3 implements Cloneable, Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 1745954590009044884L;
    private String name;
    private Date birthday;

    public Sheep3(String name, Date birthday) {
        super();
        this.name = name;
        this.birthday = birthday;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

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

测试代码:

package cn.zzit.prototype;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;

/**
 * 测试深复制 使用序列化和反序列化实现
 * 
 * @author yufu
 *
 */
public class Client3 {

    public static void main(String[] args) throws Exception {
        Date date = new Date(12366521155L);
        Sheep3 s1 = new Sheep3("多利羊", date);
        System.out.println("s1对象:" + s1);
        System.out.println("s1对象的名字:" + s1.getName());
        System.out.println("s1对象的生日:" + s1.getBirthday());
        // 序列化将s1对象写入流中
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(s1);
        byte[] b = bos.toByteArray();
        oos.close();
        bos.close();
        date.setTime(55521452236L);
        System.out.println("修改s1对象的生日:" + s1.getBirthday());

        // 反序列化从流中读出之前写入流中的数据
        ByteArrayInputStream bis = new ByteArrayInputStream(b);
        ObjectInputStream ois = new ObjectInputStream(bis);
        Sheep3 s2 = (Sheep3) ois.readObject();
        ois.close();
        bis.close();

        System.out.println("克隆的s2对象:" + s2);
        System.out.println("克隆的s2对象:" + s2.getName());
        System.out.println("克隆的s2对象:" + s2.getBirthday());
    }

}

输出结果:

s1对象:cn.zzit.prototype.Sheep3@15db9742
s1对象的名字:多利羊
s1对象的生日:Sun May 24 11:08:41 CST 1970
修改s1对象的生日:Tue Oct 05 22:37:32 CST 1971
克隆的s2对象:cn.zzit.prototype.Sheep3@6d311334
克隆的s2对象:多利羊
克隆的s2对象:Sun May 24 11:08:41 CST 1970

由输出结果同样可以看到,即使s1对象发生了变化,但是由于对象实现了深复制,所以克隆得到的对象s2并未随着s1的变化而变化。
比较深克隆与浅克隆:
浅克隆相当于复制了对象地址的引用,如果引用的值发生了改变,克隆得到的对象也随之发生变化;深克隆相当于复制了最先存储在那个内存地址上的值,如果克隆发生在那个值改变之前,克隆得到的对象并不会随着原有值的改变而改变。
最后,咱们简单的说一下克隆方式的应用场景,一般情况下克隆方式会用在对象的创建比较频繁,而且创建一次对象比较耗时的情况下。
实现代码:

package cn.zzit.prototype;

public class CloneSheep implements Cloneable {

    public CloneSheep() {
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

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

}

测试代码:

package cn.zzit.prototype;

public class Client4 {
    public static void testNew(int size) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < size; i++) {
            CloneSheep cs = new CloneSheep();
        }
        long end = System.currentTimeMillis();
        System.out.println("使用new创建对象耗时:" + (end - start) + "毫秒");
    }

    public static void testClone(int size) throws Exception {
        long start = System.currentTimeMillis();
        CloneSheep cs = new CloneSheep();
        for (int i = 0; i < size; i++) {
            CloneSheep cs2 = (CloneSheep) cs.clone();
        }
        long end = System.currentTimeMillis();
        System.out.println("使用克隆方式创建对象耗时:" + (end - start) + "毫秒");
    }

    public static void main(String[] args) throws Exception {
        testNew(1000);
        testClone(1000);
    }

}

输出结果:

使用new创建对象耗时:10334毫秒
使用克隆方式创建对象耗时:10毫秒
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值