Prototype 原型模式

模式定义
Prototype原型模式将创建一个对象定义为一个原型实例,并且通过拷贝这些原型来创建新的相似的对象。

使用范围

  • 当需要创建的一组对象在组织结构与内部实现上有很强的相似性时
  • 原型与克隆后的对象互不相干

使用方法

对于原型Prototype我们可以将它定义为抽象类,实现了Cloneable接口的方法Clone()。所有的它的子类将会拥有父类的Clone方法并返回自己的一个对象拷贝。这里涉及到一个Shallow Clone和Deep Clone的区别,Shallow Clone是对原型对象的一个引用,不管改变原型还是克隆后的对象的值,都会影响对方相应的值;Deep Clone会克隆所有Prototype内包含的所有对象(非基本数据类型),克隆后的副本与原型不共享相同的内存地址,人为地修改其中一方不会影响另一方。

举例说明
假设需要建设一个房子,房子需要有房间和花园。这里定义House对象而非用基本数据类型是为了说明Deep Clone的方法,因此House实现了Cloneable的Clone方法。如果要演示Shallow Clone,则无须实现Cloneable接口。

public class House implements Cloneable {
String room;
String garden;

public String getRoom() {
return room;
}

public void setRoom(String room) {
this.room = room;
}

public String getGarden() {
return garden;
}

public void setGarden(String garden) {
this.garden = garden;
}

public Object clone() {
House object = null;
try {
object = (House) super.clone();
} catch (CloneNotSupportedException exception) {
System.err.println("House not Cloneable");
}
return object;
}
}

AbstractArchitect顾名思义就是一个抽象类的建筑师,他是一个原型,实现Cloneable接口的Clone方法,为了实现对象的Shallow Clone。

public abstract class AbstractArchitect implements Cloneable {
House house = new House();

public abstract void buildRoom(String room);

public abstract void buildGarden(String garden);

public Object clone() {
AbstractArchitect object = null;
try {
object = (AbstractArchitect) super.clone();
} catch (CloneNotSupportedException exception) {
System.err.println("AbstractArchitect not Cloneable");
}
return object;
}
}

Architect是实例化的子类。

public class Architect extends AbstractArchitect {
public void buildRoom(String room) {
house.setRoom(room);
}

public void buildGarden(String garden) {
house.setGarden(garden);
}
}

客户端代码演示了如何实现Shallow Clone。

public class Client {
public static void main(String args[]) {
System.out.println("Shallow Clone");
AbstractArchitect a1 = new Architect();
a1.buildRoom("4 rooms");
a1.buildGarden("beautiful garden");

AbstractArchitect a2 = (AbstractArchitect) a1.clone();

System.out.println("A1:" + a1.house.getRoom() + "," + a1.house.getGarden());
System.out.println("A2:" + a2.house.getRoom() + "," + a2.house.getGarden());

a1.buildRoom("50 rooms");
a1.buildGarden("ugly garden");

System.out.println("A1:" + a1.house.getRoom() + "," + a1.house.getGarden());
System.out.println("A2:" + a2.house.getRoom() + "," + a2.house.getGarden());
}
}

运行结果为:

Shallow Clone
A1:4 rooms,beautiful garden
A2:4 rooms,beautiful garden
A1:50 rooms,ugly garden
A2:50 rooms,ugly garden

我们可以看到a2克隆了a1,其后a1改变了其内部对象的属性值,a2也跟着改变了,原因在于a2克隆了a1,但是没有克隆a1内部的一个复杂对象即House,因为在AbstractArchitect的Clone()内没有对House进行Clone(),因此 a2和a1都包含了对同一个House对象的引用。

一般情况地下,通常的编程都会要求能克隆原型的一个初始的副本,其后各自对象内部的值互不影响,为实现这种理想状况,需要采用Deep Clone方法,克隆原型内的所有复杂对象。

定义一个深度克隆的原型DeepCloneAbstractArchitect,在方法Clone()中实现了内部对象的再Clone,即object.house.clone();

public abstract class DeepCloneAbstractArchitect implements Cloneable {
House house = new House();

public abstract void buildRoom(String room);

public abstract void buildGarden(String garden);

public Object clone() {
DeepCloneAbstractArchitect object = null;
try {
object = (DeepCloneAbstractArchitect) super.clone();
house = (House) object.house.clone();
} catch (CloneNotSupportedException exception) {
System.err.println("DeepCloneAbstractArchitect not Cloneable");
}
return object;
}

子类DeepCloneArchitect

public class DeepCloneArchitect extends DeepCloneAbstractArchitect {
public void buildRoom(String room) {
house.setRoom(room);
}

public void buildGarden(String garden) {
house.setGarden(garden);
}
}

客户端实现原型的深度克隆

public class Client {
public static void main(String args[]) {
System.out.println("/nDeep Clone");
DeepCloneAbstractArchitect b1 = new DeepCloneArchitect();
b1.buildRoom("4 rooms");
b1.buildGarden("beautiful garden");

DeepCloneAbstractArchitect b2 = (DeepCloneAbstractArchitect) b1.clone();

System.out.println("B1:" + b1.house.getRoom() + "," + b1.house.getGarden());
System.out.println("B2:" + b2.house.getRoom() + "," + b2.house.getGarden());

b1.buildRoom("50 rooms");
b1.buildGarden("ugly garden");

System.out.println("B1:" + b1.house.getRoom() + "," + b1.house.getGarden());
System.out.println("B2:" + b2.house.getRoom() + "," + b2.house.getGarden());


}
}

结果为:

Deep Clone
B1:4 rooms,beautiful garden
B2:4 rooms,beautiful garden
B1:50 rooms,ugly garden
B2:4 rooms,beautiful garden

可见b2保存了b1的一个初始副本,以后两个对象互不相关,真正实现了Prototype的初衷。

类图如下:

下载示例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值