原型模式Prototype是指将一个对象作为原型模板,根据它进行复制,克隆,产生一个和原型对象相似的新的对象。本文将通过对对象的浅复制与深复制的概念与具体实现,进行讲述,并通过测试类类代码展示二者区别。在JAVA语言中,复制对象是通过实现Cloneable 接口来实现的。
先来建立原型类,Photo类
Code:
public class Photo implements Cloneable{ @Override public Object clone() throws CloneNotSupportedException { Photo photo = (Photo) super.clone(); return photo; } }这是一个简单的原型类,仅需要实现Cloneable接口,覆写clone方法即可。这里引出Clone的两种方式:
浅复制:根据一个对象复制,得到的新的对象,其基本数据类型都会重新创建,但是引用类型,与原对象拥有相同的指向。
深复制:根据一个对象复制,得到的新的对象,除了基本数据类型重建,引用类型也都是重新创建的,也就是说深复制是对原型对象进行了完全彻底的复制,而浅复制不彻底。
这里通过代码分别实现浅复制和深复制
为Photo 类新增两个属性参数,记录其是否高清照片,拍摄地点:
public class Photo implements Cloneable, Serializable { private PhotoLocation mLocation; public Photo() { mLocation = new PhotoLocation(); } public Photo(PhotoLocation location) { this.mLocation = location; } public boolean ismIsHighQuality() { return mIsHighQuality; } public void setmIsHighQuality(boolean mIsHighQuality) { this.mIsHighQuality = mIsHighQuality; } private boolean mIsHighQuality = true; public PhotoLocation getmLocation() { return mLocation; } public void setmLocation(PhotoLocation mLocation) { this.mLocation = mLocation; } @Override public Object clone() throws CloneNotSupportedException { Photo photo = (Photo) super.clone(); return photo; } public Object deepClone() throws IOException, ClassNotFoundException { /* 写入当前对象的二进制流 */ ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); /* 读出二进制流产生的新对象 */ ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return ois.readObject(); } }
这里我们要实现深复制,使用的方法是采用流的形式读入当前对象的二进制输入,再写出二进制数据对应的对象
PhotoLocation 类:
public class PhotoLocation implements Serializable { String ID; String Name; public PhotoLocation() { } public PhotoLocation(String id, String name) { setID(id); setName(name); } public String getName() { return Name; } public void setName(String name) { Name = name; } public String getID() { return ID; } public void setID(String ID) { this.ID = ID; } }最后写测试类,显示浅复制与深复制的区别:输出结果:public class WorkClass { public void test() { Photo photo = new Photo(new PhotoLocation("010","Beijing")); Photo photoCopy = null; Photo photoDeepcopy = null; try { photoCopy = (Photo) photo.clone(); photoDeepcopy = (Photo) photo.deepClone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } if (null != photo && null != photoCopy && null != photoDeepcopy) { System.out.println(String.format("photo.getmLocation().getName()=%s,photoCopy.getmLocation().getName()=%s,,photoDeepcopy.getmLocation().getName()=%s", photo.getmLocation().getName(), photoCopy.getmLocation().getName(), photoDeepcopy.getmLocation().getName())); System.out.println(String.format("photo.ismIsHighQuality()=%s,photoCopy.ismIsHighQuality()=%s,,photoDeepcopy.ismIsHighQuality()=%s", photo.ismIsHighQuality(), photoCopy.ismIsHighQuality(), photoDeepcopy.ismIsHighQuality())); photoCopy.getmLocation().setName("Shanghai"); photoCopy.setmIsHighQuality(false); System.out.println(String.format("photo.getmLocation().getName()=%s,photoCopy.getmLocation().getName()=%s,,photoDeepcopy.getmLocation().getName()=%s", photo.getmLocation().getName(), photoCopy.getmLocation().getName(), photoDeepcopy.getmLocation().getName())); System.out.println(String.format("photo.ismIsHighQuality()=%s,photoCopy.ismIsHighQuality()=%s,,photoDeepcopy.ismIsHighQuality()=%s", photo.ismIsHighQuality(), photoCopy.ismIsHighQuality(), photoDeepcopy.ismIsHighQuality())); photoDeepcopy.getmLocation().setName("Hangzhou"); photoDeepcopy.setmIsHighQuality(false); System.out.println(String.format("photo.getmLocation().getName()=%s,photoCopy.getmLocation().getName()=%s,,photoDeepcopy.getmLocation().getName()=%s", photo.getmLocation().getName(), photoCopy.getmLocation().getName(), photoDeepcopy.getmLocation().getName())); System.out.println(String.format("photo.ismIsHighQuality()=%s,photoCopy.ismIsHighQuality()=%s,,photoDeepcopy.ismIsHighQuality()=%s", photo.ismIsHighQuality(), photoCopy.ismIsHighQuality(), photoDeepcopy.ismIsHighQuality())); } } }
I/System.out: photo.getmLocation().getName()=Beijing,photoCopy.getmLocation().getName()=Beijing,,photoDeepcopy.getmLocation().getName()=Beijing I/System.out: photo.ismIsHighQuality()=true,photoCopy.ismIsHighQuality()=true,,photoDeepcopy.ismIsHighQuality()=true I/System.out: photo.getmLocation().getName()=Shanghai,photoCopy.getmLocation().getName()=Shanghai,,photoDeepcopy.getmLocation().getName()=Beijing I/System.out: photo.ismIsHighQuality()=true,photoCopy.ismIsHighQuality()=false,,photoDeepcopy.ismIsHighQuality()=true I/System.out: photo.getmLocation().getName()=Shanghai,photoCopy.getmLocation().getName()=Shanghai,,photoDeepcopy.getmLocation().getName()=Hangzhou I/System.out: photo.ismIsHighQuality()=true,photoCopy.ismIsHighQuality()=false,,photoDeepcopy.ismIsHighQuality()=false
分析结果:可以看出photo作为原型对象,其属性参数Location(引用类型)会随着其浅复制对象photoCopy而改变,而不会随着其深复制对象photoDeepcopy而改变,另外基础类型boolean IsHighQuality 一直不会随复制对象改变。