java设计模式之原型模式

来源:互联网 发布:云霄网络 编辑:程序博客网 时间:2024/05/20 09:06

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@15db9742s1对象的名字:多利羊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@15db9742s1对象的名字:多利羊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@15db9742s1对象的名字:多利羊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毫秒