<其它设计模式介绍及案例源码下载 >
简介:原型模式(Prototype Pattern)是用于创建重复的对象,并且与重新new对象相比较,性能更高。这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。
主要解决:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
优点: 1、性能提高。 2、逃避构造函数的约束。
缺点: 1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。 2、必须实现 Cloneable 接口。
使用场景: 1、资源优化场景。 2、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。 3、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。 4、一个对象多个修改者的场景。5、在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与 Java 融为浑然一体,大家可以随手拿来使用。
实例分析:
方案一(通过实现Cloneable接口实现深浅复制,代码如下):
public class MainClassCloneAble implements Cloneable{ String name; AccompanyCloneable acA; public MainClassCloneAble() { super(); // TODO Auto-generated constructor stub } public String getName() { return name; } public void setName(String name) { this.name = name; } public AccompanyCloneable getAcA() { return acA; } public void setAcA(AccompanyCloneable acA) { this.acA = acA; } @Override public String toString() { return "MainClass [name=" + name + ", acA=" + acA + "]"; } @Override public Object clone() { MainClassCloneAble mc=null; try { mc=(MainClassCloneAble) super.clone(); //这个语句不能缺,否则即使MainClass的引用属性对应的类实现了Cloneable也是浅复制 mc.acA=(AccompanyCloneable) acA.clone(); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return mc; } } public class AccompanyCloneable implements Cloneable { String name; String gender ; public AccompanyCloneable(String name, String gender) { super(); this.name = name; this.gender = gender; } public AccompanyCloneable() { super(); // TODO Auto-generated constructor stub } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } @Override public String toString() { return "AccompanyA [name=" + name + ", gender=" + gender + "]"; } @Override protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub return super.clone(); } } public class TestClass { public static void main(String[] args) { //方案一:通过实现cloneable实现深复制 AccompanyCloneable acA=new AccompanyCloneable("aa","bb"); MainClassCloneAble mc=new MainClassCloneAble(); mc.setName("main"); mc.setAcA(acA); MainClassCloneAble mc2=(MainClassCloneAble) mc.clone(); mc2.getAcA().setName("dd"); System.out.println("mc对象:"+mc); System.out.println("mc2对象:"+mc2); } }
评价:这种方法实现深复制,当主类的成员变量中只有少量的引用变量时倒还好,当数量太多则会所有涉及到的随从类都要实现Cloneable接口,并且重写clone()方法,而且需要注意的是,在主类的clone()中需要对所有引用属性调用其各自的clone()方法,否则相应的引用属性无法实现深度复制,显然造成不便 。
方案二(通过实现Serializable接口实现深复制,代码如下):
public class MainClassSerializable implements Serializable{ String name; AccompanySerializable acs; public MainClassSerializable() { super(); // TODO Auto-generated constructor stub } public String getName() { return name; } public void setName(String name) { this.name = name; } public AccompanySerializable getAcs() { return acs; } public void setAcs(AccompanySerializable acs) { this.acs = acs; } @Override public String toString() { return "MainClass [name=" + name + ", acs=" + acs + "]"; } public Object deepClone() { Object o=null; ObjectInputStream oi=null; try { //将对象写到流里 ByteArrayOutputStream bo=new ByteArrayOutputStream(); ObjectOutputStream oo=new ObjectOutputStream(bo); oo.writeObject(this); //从流里读出来 ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray()); oi=new ObjectInputStream(bi); o=(oi.readObject()); oo.close(); oi.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return o; } } public class AccompanySerializable implements Serializable { String name; String gender ; public AccompanySerializable(String name, String gender) { super(); this.name = name; this.gender = gender; } public AccompanySerializable() { super(); // TODO Auto-generated constructor stub } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } @Override public String toString() { return "AccompanyA [name=" + name + ", gender=" + gender + "]"; } @Override protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub return super.clone(); } } public class TestClass { public static void main(String[] args) { //方案二:通过实现serializable接口将对象序列化 AccompanySerializable acs=new AccompanySerializable("ss","ee"); MainClassSerializable ms=new MainClassSerializable(); ms.setName("main"); ms.setAcs(acs); MainClassSerializable ms2=(MainClassSerializable) ms.deepClone(); ms2.getAcs().setName("clone"); System.out.println("ms对象:"+ms); System.out.println("ms2对象:"+ms2); } }
评价:对象以及对象内部所有引用到的对象都是可串行化的,否则,就需要仔细考察那些不可串行化的对象可否设成transient,从而将之排除在复制过程之外。 对象写到一个字节流中,再从字节流中将其取出来,这样就可以重建一个新对象,该对象与母对象之间不存在引用共享的问题,也就相当于深拷贝了一个新对象,这种方法相对于通过Cloneable来说更简便。