1.原型模式的定义与特点
原型(Prototype)模式是一种对象创建型模式,用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。
原型模式的特点:
- 由原型对象自身创建目标对象。也就是说,对象创建这一动作发自原型对象本身
- 目标对象是原型对象的一个克隆。也就是说,通过Prototype模式创建的对象,不仅仅与原型对象具有相同的结构,还与原型对象具有相同的值
- 根据对象克隆深度层次的不同,有浅度克隆与深度克隆。
浅度克隆:克隆的是对象的引用
深度克隆:克隆的是对象的值
2.原型模式的结构和实现
模式的结构:
原型模式包含以下主要角色:
- 抽象原型类:规定了具体原型对象必须实现的接口。
- 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
- 访问类:使用具体原型类中的 clone() 方法来复制新的对象。
结构图如下:
模式的实现:
原型模式的克隆分为浅克隆和深克隆,Java 中的 Object 类提供了浅克隆的 clone() 方法,具体原型类只要实现 Cloneable 接口就可实现对象的浅克隆,这里的 Cloneable 接口就是抽象原型类。其代码如下:
/**
* 原型模式测试类
*/
public class PrototypeTest {
public static void main(String[] args) throws CloneNotSupportedException {
ProtoType protoType1 = getProtoType();
ProtoType protoType2 = getProtoType();
test("浅度克隆:克隆的是对象的引用", protoType1, protoType1.clone());
test("\n深度克隆:克隆的是对象的值", protoType2, protoType2.clone2());
}
private static ProtoType getProtoType() {
List<String> ids = new ArrayList<>();
ids.add("b");
ids.add("c");
ProtoType protoType = new ProtoType("a", ids, new ProtoSubType("李四"));
return protoType;
}
private static void test(String pritMsg, ProtoType protoType1, ProtoType protoType2) {
System.out.println(pritMsg);
System.out.println(protoType1 == protoType2);
System.out.println("protoType1 = " + protoType1.toString() + " / protoType2 = " + protoType2.toString());
protoType2.id = "x";
protoType2.ids.add("y");
protoType2.subType.name = "王五";
System.out.println("protoType1 = " + protoType1.toString() + " / protoType2 = " + protoType2.toString());
}
}
程序运行结果:
浅度克隆:克隆的是对象的引用
false
protoType1 = {id='a', ids=[b, c], subType={name='李四'}} / protoType2 = {id='a', ids=[b, c], subType={name='李四'}}
protoType1 = {id='a', ids=[b, c, y], subType={name='王五'}} / protoType2 = {id='x', ids=[b, c, y], subType={name='王五'}}
深度克隆:克隆的是对象的值
false
protoType1 = {id='a', ids=[b, c], subType={name='李四'}} / protoType2 = {id='a', ids=[b, c], subType={name='李四'}}
protoType1 = {id='a', ids=[b, c], subType={name='李四'}} / protoType2 = {id='x', ids=[b, c, y], subType={name='王五'}}
/**
* 原型类
*/
public class ProtoType implements Cloneable {
public String id;
public List<String> ids;
public ProtoSubType subType;
public ProtoType(String id, List<String> ids, ProtoSubType subType) {
this.id = id;
this.ids = ids;
this.subType = subType;
}
/**
* 浅度克隆:克隆的是对象的引用
*/
public ProtoType clone() throws CloneNotSupportedException {
return (ProtoType) super.clone();
}
/**
* 深度克隆:克隆的是对象的值
*/
public ProtoType clone2() throws CloneNotSupportedException {
ProtoType protoType = (ProtoType) super.clone();
List<String> ids = new ArrayList<String>();
if (this.ids != null) {
ids.addAll(this.ids);
}
protoType.ids = ids;
protoType.subType = (this.subType.clone());
return protoType;
}
@Override
public String toString() {
return "{" + "id='" + id + '\'' + ", ids=" + ids + ", subType=" + subType.toString() + '}';
}
}
/**
* 原型类里面的子类对象
*/
public class ProtoSubType implements Cloneable {
public String name;
public ProtoSubType(String name) {
this.name = name;
}
public ProtoSubType clone() throws CloneNotSupportedException {
return (ProtoSubType) super.clone();
}
@Override
public String toString() {
return "{" + "name='" + name + '\'' + '}';
}
}
3.原型模式应用场景
- 在创建对象的时候,我们不只是希望被创建的对象继承其基类的基本结构,还希望继承原型对象的数据
- 希望对目标对象的修改不影响既有的原型对象(深度克隆的时候可以完全互不影响)
- 隐藏克隆操作的细节。很多时候,对对象本身的克隆需要涉及到类本身的数据细节