@BertLee
2017-08-09T10:03:06.000000Z
字数 2871
阅读 1321
原型模式根据原型对象可以创建出完全一模一样的相同对象。
原型模式基本分为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;}@Overridepublic 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 {@Testpublic 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()));}@Testpublic 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
能力有限,如有纰漏,请在评论区指出,老朽虽一把年纪,必当感激涕零,泪如雨下。若有满嘴喷粪撕逼者,一律拉黑、举报,并移交阎王爷处理。