@BertLee
2017-08-09T18:03:06.000000Z
字数 2871
阅读 1146
原型模式根据原型对象可以创建出完全一模一样的相同对象。
原型模式基本分为2类:
- 简单式原型模式:适用原型对象数目较少且比较固定;创建后直接被客户端使用
- 登记式原型模式:适用创建的原型对象数目不固定;复制对象前,先从容器中查找是否已经克隆,没有的话直接复制,并放入,有的话直接从容器中取出。
复制形式可分为2类:
- 浅复制:按值复制,对于引用类型,只是把地址复制了一份,复制后,新引用与旧引用指向的是同一个对象
- 深复制:基本数据类型按值复制,对于引用类型,其指向的对象会在内存中重新复制一份,复制后,新引用与旧引用指向的是不同的对象,但内容相同。深复制存在2个问题,1是可能会出现循环引用,2是复制的深度,具体到那一层是不确定的。
原型模式的结构如下图:
套路:
1. 实现Cloneable接口;深复制还要实现Serializable接口
2. 浅复制要实现clone方法
/**
* 需要克隆的原型类
*/
public class Person implements Cloneable,Serializable{
private String name;
private Integer age;
private Date birthday;
public Person(String name, Integer age, Date birthday) {
this.name = name;
this.age = age;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", birthday=" + birthday +
'}';
}
/**
* 浅复制
* 1.clone()源自Object,访问修饰符为protected,这里改为public
* 2.Person要实现标识接口Cloneable
*/
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
/**
* 深复制
* 1.Person实现Serializable接口
*/
public Object deepClone() throws IOException, ClassNotFoundException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
return new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray())).readObject();
}
}
/**
* 原型管理器
*/
public class PersonPrototypeManager {
private static final Map<String,Person> personMap = new HashMap<String, Person>();
private PersonPrototypeManager(){}
public static synchronized void put(String personId,Person person){
personMap.put(personId,person);
}
public static synchronized void remove(String personId){
personMap.remove(personId);
}
public static synchronized Person get(String personId){
return personMap.get(personId);
}
}
/**
* 测试原型模式
*/
public class PrototypeTest {
@Test
public void testClone() throws CloneNotSupportedException {
//浅复制
Person oldPerson = new Person("田小娥", 24, new Date());
Person newPerson = (Person) oldPerson.clone();
System.out.println(newPerson);
System.out.println(oldPerson == newPerson);
//注册到原型管理器中
PersonPrototypeManager.put(newPerson.getName(),newPerson);
System.out.println(PersonPrototypeManager.get(newPerson.getName()));
}
@Test
public void testDeepClone() throws IOException, ClassNotFoundException {
//深复制
Person oldPerson = new Person("田小娥", 24, new Date());
Person newPerson = (Person) oldPerson.deepClone();
System.out.println(newPerson);
System.out.println(oldPerson == newPerson);
//注册到原型管理器中
PersonPrototypeManager.put(newPerson.getName(),newPerson);
System.out.println(PersonPrototypeManager.get(newPerson.getName()));
}
}
吹牛:原型模式可以在不改变接口的情况下,动态的改变实现类对象。缺点是对于不支持序列化的类如Thread对象和Socket对象无能为力;深复制时可能会出现循环引用,导致程序奔溃。
感谢java-my-file,撰写本文参考了其文章《JAVA与模式》之原型模式。
转载时,请注明出处,这是人格的一种体现。
https://www.zybuluo.com/BertLee/note/843705
能力有限,如有纰漏,请在评论区指出,老朽虽一把年纪,必当感激涕零,泪如雨下。若有满嘴喷粪撕逼者,一律拉黑、举报,并移交阎王爷处理。