原型模式是一种比较简单的设计模式,也非常的容易理解,属于创建型设计模式的一种,只实现一个接口,重写一个方法即可完成原型模式。那么我们就来看看吧。
用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
创建一些大对象,比较耗时的对象的时候,可以使用原型模式提高创建对象的效率。
1、实现Cloneable接口,在java中有一个Cloneable接口,它的作用只有一个,就是通知虚拟机可以安全的在实现了此接口的类上使用clone()方法。如果你想看下这个接口,其实可以告诉你,并没有什么可看的,只是一个标识接口,实现此接口就是表示了这个类具有被Clone的能力,如果没有实现此接口,而去使用clone(),就会抛出CloneNotSupportedException异常。
2、重写Object类中的clone方法。Java中,所有类的父类都是Object类,Object类中有一个clone方法,作用是返回对象的一个拷贝,但是其作用域protected类型的,一般的类无法调用,因此,Prototype类需要将clone方法的作用域修改为public类型。
下面就以羊来为原型克隆多利
代码实现
package cn.wong.pattern.prototype; import java.util.Date; public class Sheep implements Cloneable { private String name; private Date birthDay; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } public Sheep() { } public Sheep(String name, Date birthDay) { 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; } } package cn.wong.pattern.prototype; import java.util.Date; public class Client { public static void main(String[] args) throws CloneNotSupportedException { Sheep s1 = new Sheep("芬兰母羊",new Date(324324234L)); System.out.println(s1); System.out.println(s1.getName()); System.out.println(s1.getBirthDay()); System.out.println("---------进行clone----------"); Sheep s2 = (Sheep)s1.clone(); System.out.println(s2); System.out.println(s2.getName()); System.out.println(s2.getBirthDay()); } }结果:
cn.wong.pattern.prototype.Sheep@4633c1aa 芬兰母羊 Mon Jan 05 02:05:24 CST 1970 ---------进行clone---------- cn.wong.pattern.prototype.Sheep@28a50395 芬兰母羊 Mon Jan 05 02:05:24 CST 1970从结果可以看出拷贝出来的是一个新的对象,并和原始对象具有相同的属性值
使用原型模式创建对象比直接new一个对象在性能上要好很多,因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。 protected native Object clone() throws CloneNotSupportedException;
使用原型模式的注意事项 1. 使用原型模式不会调用类的构造方法,因为它是直接在内存中进行复制的。 2. 深拷贝和浅拷贝
Object类的clone方法只会拷贝对象中的8中基本数据类型,对于数组、日期、容器对象、引用对象等都不会拷贝,这就是浅拷贝。如果要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝
浅拷贝:
package cn.wong.pattern.prototype; import java.util.Date; public class Sheep implements Cloneable { private String name; private Date birthDay; @Override public Object clone() throws CloneNotSupportedException { Object obj = super.clone(); /*Sheep s = (Sheep)obj; s.birthDay=(Date) this.birthDay.clone();*/ return obj; } public Sheep() { } public Sheep(String name, Date birthDay) { 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; } } package cn.wong.pattern.prototype; import java.util.Date; public class Client { public static void main(String[] args) throws CloneNotSupportedException { Date date = new Date(324324234L); Sheep s1 = new Sheep("芬兰母羊",date); System.out.println("---------打印s1的信息----------"); System.out.println(s1); System.out.println(s1.getName()); System.out.println(s1.getBirthDay()); //进行复制 Sheep s2 = (Sheep)s1.clone(); //修改s1所指向的时间 date.setTime(23432454354L); System.out.println("\n---------再次打印s1的信息----------"); System.out.println(s1.getName()); System.out.println(s1.getBirthDay()); System.out.println("\n---------打印s2的信息----------"); System.out.println(s2); System.out.println(s2.getName()); System.out.println(s2.getBirthDay()); } }结果:
---------打印s1的信息---------- cn.wong.pattern.prototype.Sheep@5df1cc1a 芬兰母羊 Mon Jan 05 02:05:24 CST 1970 ---------再次打印s1的信息---------- 芬兰母羊 Tue Sep 29 13:00:54 CST 1970 ---------打印s2的信息---------- cn.wong.pattern.prototype.Sheep@7a0ec850 芬兰母羊 Tue Sep 29 13:00:54 CST 1970发现s2的信息是改变时间后的,我们知道,clone是在修改时间前进行。所以由此我们可以知道引用类型对象不会进行拷贝,s1、s2两个对象同时都是指向同一个Date,这就是浅拷贝。
深拷贝:
如果要实现深拷贝,必须将引用对象另行拷贝。而对于java的大部分的类都实现了Cloneable接口,所以深拷贝并不困难。
修改Sheep中clone方法
@Override public Object clone() throws CloneNotSupportedException { Object obj = super.clone(); Sheep s = (Sheep)obj; s.birthDay=(Date) this.birthDay.clone(); return obj; }测试不变
package cn.wong.pattern.prototype; import java.util.Date; public class Client { public static void main(String[] args) throws CloneNotSupportedException { Date date = new Date(324324234L); Sheep s1 = new Sheep("芬兰母羊",date); System.out.println("---------打印s1的信息----------"); System.out.println(s1); System.out.println(s1.getName()); System.out.println(s1.getBirthDay()); //进行复制 Sheep s2 = (Sheep)s1.clone(); //修改s1所指向的时间 date.setTime(23432454354L); System.out.println("\n---------再次打印s1的信息----------"); System.out.println(s1.getName()); System.out.println(s1.getBirthDay()); System.out.println("\n---------打印s2的信息----------"); System.out.println(s2); System.out.println(s2.getName()); System.out.println(s2.getBirthDay()); } }结果
---------打印s1的信息---------- cn.wong.pattern.prototype.Sheep@2d8eef25 芬兰母羊 Mon Jan 05 02:05:24 CST 1970 ---------再次打印s1的信息---------- 芬兰母羊 Tue Sep 29 13:00:54 CST 1970 ---------打印s2的信息---------- cn.wong.pattern.prototype.Sheep@60813aca 芬兰母羊 Mon Jan 05 02:05:24 CST 1970