您从图书馆的期刊从发现了几篇您感兴趣的文章,由于这是图书馆的书,您不可以直接在书中作记号或写字,所以您将当中您所感兴趣的几个主题影印出来,这下子您就可在影印的文章上画记重点。
Prototype模式的作用有些类似上面的描述,您在父类别中定义一个clone()方法,而在子类别中重新定义它,当客户端对于所产生的物件有兴趣并想加以利用,而您又不想破坏原来的物件,您可以产生一个物件的复本给它。
Prototype具有展示的意味,就像是展览会上的原型车款,当您对某个车款感兴趣时,您可以购买相同款示的车,而不是车展上的车。
在软体设计上的例子会更清楚的说明为何要进行物件复制,假设您要设计一个室内设计软体,软体中有一个展示家具的工具列,您只要点选工具列就可以产生一个家具复本,例如一张椅子或桌子,您可以拖曳这个复制的物件至设计图中,随时改变它的位置、颜色等等,当您改变设计图中的物件时,工具列上的原型工具列是不会跟着一起改变的,这个道理是无需解释的。
下面的 UML 类别图表示了上述的简单概念:
CircleTable与SquareTable继承了AbstractFurniture,并实作clone方法,用于传回本身的复制品:
- CircleTable.java
import java.awt.*;
public class CircleTable extends AbstractFurniture {
protected Point center;
public void setCenter(Point center) {
this.center = center;
}
protected Object clone ()
throws CloneNotSupportedException {
Object o = super.clone();
if(this.center != null) {
((CircleTable) o).center = (Point) center.clone();
}
return o;
}
public void draw() {
System.out.println("\t圆桌\t中心:(" + center.getX()
+ ", " + center.getY()+ ")");
}
}
- SquareTable.java
import java.awt.*;
public class SquareTable extends AbstractFurniture {
protected Rectangle rectangle;
public void setRectangle(Rectangle rectangle) {
this.rectangle = rectangle;
}
protected Object clone ()
throws CloneNotSupportedException {
Object o = super.clone();
if(this.rectangle != null) {
((SquareTable) o).rectangle = (Rectangle) rectangle.clone();
}
return o;
}
public void draw() {
System.out.print("\t方桌\t位置:(" + rectangle.getX()
+ ", " + rectangle.getY()+ ")");
System.out.println(" / 宽高:(" +
rectangle.getWidth()
+ ", " + rectangle.getHeight()+ ")");
}
}
House是个虚拟的房屋物件,从Prototype复制出来的物件加入至House中:
再来是应用程式本身:
- Application.java
import java.awt.*;
public class Application {
private AbstractFurniture circleTablePrototype;
public void setCircleTablePrototype(
AbstractFurniture circleTablePrototype) {
this.circleTablePrototype = circleTablePrototype;
}
public void runAppExample() throws Exception {
House house = new House();
CircleTable circleTable = null;
// 从工具列选择一个家具加入房子中
circleTable =
(CircleTable) circleTablePrototype.clone();
circleTable.setCenter(new Point(10, 10));
house.addFurniture(circleTable);
// 从工具列选择一个家具加入房子中
circleTable =
(CircleTable) circleTablePrototype.clone();
circleTable.setCenter(new Point(20, 30));
house.addFurniture(circleTable);
}
public static void main(String[] args) throws Exception {
Application application = new Application();
application.setCircleTablePrototype(
new CircleTable());
application.runAppExample();
}
}
Java中的clone()方法是继承自Object,AbstractFurniture的子类别则override这个clone()方法,以复制其本身并传回。
下图为Prototype模式的类别结构图:
在 Gof 的设计模式书中给出一个原型模式的应用:一个通用的图型编辑器 Framework。在这个
Framework中有一个工具列,您可以在上面选择音乐符号以加入乐谱中,并可以随时调整音乐符号的位置等等。
图型编辑器Framework是通用的,然而它并不知道这些音乐符号的型态,有人或许会想到继承图型编辑器Framework来为每个音乐符号设计一个框架子类别,但由于音乐符号的种类很多,这会产生相当多的子类别,为了避免这种情况,可以透过Prototype模式来减少子类别的数目,可以设计出以下的结构:
依照这个结构,图型编辑器的Framework可以独立于要套用的特定类别之外,虽然不知道被复制传回的对象型态是什么,但总可以按照
Graphics所定义的介面来操作这些物件。
|