概述
原型模式(Prototype Pattern):使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式是一种对象创建型模式。
问题
当对象的构造方法非常的复杂,生成新的对象非常的复杂,消耗资源的情况下,我们如何创建对象。
解决方案
通过复制一个指定类型的对象来创建更多同类型的对象。这个被指定的对象就是原型。
复制对象的数据结构。
结构
- 客户端(Client):使用原型的客户端程序
- 抽象原型(Prototype):规定了原型对象必须实现的接口(如浅克隆必须实现Cloneable接口)
- 具体原型(concrePrototype): 抽象原型的具体实现,在客户端使用具体原型,被复制的对象。
java中的克隆模式
浅克隆
浅克隆中
- 原型对象的成员变量是值类型(基本类型),将复制一份给克隆对象。
- 原型对象的成员变量是引用类型,将引用对象的地址复制一份给克隆对象。就是说两个属性指向同一个对象。对一个属性的修改将影响另外一个属性。
注意:不可变类型对象(如:String)属性,改变会指向新生成一个新的对象。
浅克隆需要实现Cloneable
接口,调用Object的clone()
方法(Object的clone()方法是native方法,使用其他语言实现的)。
深克隆
深克隆中无论是基本类型还是引用类型的成员变量都会完整的被复制下来,复制对象的引用类型成员变量地址和原型对象的不相同。
深克隆是通过序列化方式和反序列化实现,序列化就是将对象转换成二进制数组,原型对象还存在内存中,然后将二进制数组进行反序列化重新再内存中生产一个对象。对象序列化需要实现Serializable
接口,需要被序列化的成员变量的类也需要实现这个接口。
示例
import java.io.*;
public class User implements Cloneable, Serializable{
private static final long serialVersionUID = -8906853582930958721L;
private int age;
private String name;
private Address address;
public User() {
}
public User(int age, String name, Address address) {
this.age = age;
this.name = name;
this.address = address;
}
/**
* 深克隆方法:实现Serializable接口,使用ObjetOutputStream和ObjectInputStream实现
* @return
*/
public User deepClone(){
User user = null;
ByteArrayOutputStream baos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bais = null;
ObjectInputStream ois = null;
try {
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(this);
bais = new ByteArrayInputStream(baos.toByteArray());
ois = new ObjectInputStream(bais);
user = (User) ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
baos = null;
bais = null;
try {
if (oos != null) oos.close();
if (ois != null) ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return user;
}
/**
* 浅克隆方法:实现Colneable接口使用继承Object类的clone方法
* @return
*/
public User weeklyClone(){
User user = null;
try {
user = (User) super.clone();
} catch (CloneNotSupportedException e) {
System.out.println("该类不支持克隆方法!");
e.printStackTrace();
}
return user;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
", address=" + address +
'}';
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
import java.io.Serializable;
public class Address implements Serializable{
private static final long serialVersionUID = 710758201802876405L;
private String name;
private int number;
public Address(String name, int number) {
this.name = name;
this.number = number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Address{" +
"name='" + name + '\'' +
", number=" + number +
'}';
}
}
public static void main(String[] args) {
testWeeklyClone();
testDeepClone();
}
public static void testDeepClone(){
Address address = new Address("上海", 111);
User xm = new User(10, "小明", address);
User xmCopy = xm.deepClone();
System.out.println("小明复制人地址与小明是否是相同对象:" +
(xmCopy.getAddress() == xm.getAddress()));
System.out.println(xm);
System.out.println(xmCopy);
address.setName("北京");
System.out.println("更改小明地址后,小明的地址:" +
xm.getAddress());
System.out.println("更改小明地址后,小明的复制人地址:" +
xmCopy.getAddress());
System.out.println("小明复制人地址与小明是否相同:" +
(xmCopy.getAddress() == xm.getAddress()));
}
public static void testWeeklyClone(){
Address address = new Address("上海", 111);
User xm = new User(10, "小明", address);
User xmCopy = xm.weeklyClone();
System.out.println(xm);
System.out.println(xmCopy);
address.setName("北京");
System.out.println("更改小明地址后,小明的复制人地址:" +
xmCopy.getAddress());
System.out.println("小明复制人地址与小明是否相同:" +
(xmCopy.getAddress() == xm.getAddress()));
}
总结
优点
- 简化复杂对象的创建
缺点
- 克隆实现比较复杂