Prototype原型模型-java设计模式5
? 一、概念:Prototype原型模式:通过复制一个或多个原型类,然后修改或填充具体的内容获得目标类的方式。如果目标类与原型类相似或者他们本身就属于一个类型组(特别是来自一个数据集合对象),则可以使用原型模式。
二、示例:游泳比赛选手列表小程序,先创建一个TimeSwimData类的列表的Vector对象,然后从中复制修改填充AgeSwimData类、SexSwimData类对象的Vector值,从而得到所需的不同的对象。
它的UML 类图为:
三、程序解析:
1.在程序主类SwimInfo类中声明了SwimData类,Swimmer类对象,引用了SwimData的子类,在其构造方法中:
public SwimInfo() { super("Prototype example"); sdata = new TimeSwimData("d:/swimmers.txt"); setGUI(); loadswList(sdata, swList); }?
?在TimeSwimmData构造方法中:
public TimeSwimData(String filename) { String s = ""; swimmers = new Vector(); InputFile f = new InputFile(filename); s= f.readLine(); while (s != null) { swimmers.addElement(new Swimmer(s)); s= f.readLine(); } f.close(); }?
?2.在共同的SwimData抽象类中声明的重要的deepClone()方法,使得子类中可以调用它得到独立的TimeSwimmData类的Vector数据。
public SwimData deepClone() { try { ByteArrayOutputStream b = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(b); out.writeObject(this);//对当前的对象做了流复制,使得当前的对象改变了。ByteArrayInputStreambIn=newByteArrayInputStream(b.toByteArray()); ObjectInputStream oi = new ObjectInputStream(bIn); return((SwimData)oi.readObject()); } catch (Exception e) { System.out.println("exception:"+e.getMessage()); e.printStackTrace(); return null; }}?
3.子类中使用对得到的Vector数据做了排序(修改)得到新的Vector数据使得它的对象拥有了新的特征。例如SexSwimData类先用构造方法获得了上述深拷贝的对象,然后用sort()方法得到了新的对象:
构造方法,其中的sd参数是TimeSwimData创建的对象:
public SexSwimData(SwimData sd) { swimdata=sd.deepClone ();//获得了流深拷贝后的对象。 female = true; }?
? sort()方法:
public void sort() { sexData = new Vector();//在对象外调用,使得对象的Vector属性保持这里的改变值 for (int i=0; i<swimdata.size (); i++) { Swimmer sw = swimdata.getSwimmer (i); if (sw.isFemale () == female ) { sexData.addElement (sw); } } }?
?从而得到了基于改变原对象Vector数据的SexSwimData类对象,实现了原型模式。
扩展:1.拷贝的形式,上述的使用ByteArrayOutputStream类的方法是对于原型类的数据比较复杂的情况下很有效的方法。当然也可以用重新声明一个数组或向量将其用原来的数据一个个的取出赋值给它,然后将其放到目标类的构造方法中实现深拷贝(这也是复制的数据成员较简单时常用的方法),如在SwimData中没有实现相应的方法,则在子类TimeSwimData类中用这样的构造方法实现对自己的拷贝,以提供给其他的子类调用它的构造方法创建独立的Vector:
public TimeSwimData(Vector sw) { //this constructor copies vector as clone swimmers = new Vector(); for (int i=0; i < sw.size (); i++) { swimmers.add (sw.elementAt (i)); } }?
?2.以上的生成相应的类的决策点是在用户单击相应的按钮时,决策点可以是一个类注册表或是原型管理器,管理有类似独立数据成员的子类(也可是管理多个对象组),它查看这些特征数据(可在运行时)并选择创建最合适的类,这是结合了Builder模式。
3.可以和工厂模式结合,使得每个具体类与其他的可用的具体类完全不同。
四、结论:
(1)在运行时可以根据需要,以复制的方式增加和删除类。
(2)可以基于程序条件,在运行时修改一个类的内部数据表示。
(3)可以在运行时指定新的对象,而无需创建一系列类和继承结构。