[关闭]
@BertLee 2017-08-09T18:03:06.000000Z 字数 2871 阅读 1146

copy神器原型模式

序言

  原型模式根据原型对象可以创建出完全一模一样的相同对象。
原型模式基本分为2类:

  1. 简单式原型模式:适用原型对象数目较少且比较固定;创建后直接被客户端使用
  2. 登记式原型模式:适用创建的原型对象数目不固定;复制对象前,先从容器中查找是否已经克隆,没有的话直接复制,并放入,有的话直接从容器中取出。

复制形式可分为2类:

  1. 浅复制:按值复制,对于引用类型,只是把地址复制了一份,复制后,新引用与旧引用指向的是同一个对象
  2. 深复制:基本数据类型按值复制,对于引用类型,其指向的对象会在内存中重新复制一份,复制后,新引用与旧引用指向的是不同的对象,但内容相同。深复制存在2个问题,1是可能会出现循环引用,2是复制的深度,具体到那一层是不确定的。

原型模式

原型模式的结构如下图:



套路:
1. 实现Cloneable接口;深复制还要实现Serializable接口
2. 浅复制要实现clone方法

  1. /**
  2. * 需要克隆的原型类
  3. */
  4. public class Person implements Cloneable,Serializable{
  5. private String name;
  6. private Integer age;
  7. private Date birthday;
  8. public Person(String name, Integer age, Date birthday) {
  9. this.name = name;
  10. this.age = age;
  11. this.birthday = birthday;
  12. }
  13. public String getName() {
  14. return name;
  15. }
  16. public void setName(String name) {
  17. this.name = name;
  18. }
  19. public Integer getAge() {
  20. return age;
  21. }
  22. public void setAge(Integer age) {
  23. this.age = age;
  24. }
  25. public Date getBirthday() {
  26. return birthday;
  27. }
  28. public void setBirthday(Date birthday) {
  29. this.birthday = birthday;
  30. }
  31. @Override
  32. public String toString() {
  33. return "Person{" +
  34. "name='" + name + '\'' +
  35. ", age=" + age +
  36. ", birthday=" + birthday +
  37. '}';
  38. }
  39. /**
  40. * 浅复制
  41. * 1.clone()源自Object,访问修饰符为protected,这里改为public
  42. * 2.Person要实现标识接口Cloneable
  43. */
  44. public Object clone() throws CloneNotSupportedException {
  45. return super.clone();
  46. }
  47. /**
  48. * 深复制
  49. * 1.Person实现Serializable接口
  50. */
  51. public Object deepClone() throws IOException, ClassNotFoundException {
  52. ByteArrayOutputStream bos = new ByteArrayOutputStream();
  53. ObjectOutputStream oos = new ObjectOutputStream(bos);
  54. oos.writeObject(this);
  55. return new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray())).readObject();
  56. }
  57. }
  1. /**
  2. * 原型管理器
  3. */
  4. public class PersonPrototypeManager {
  5. private static final Map<String,Person> personMap = new HashMap<String, Person>();
  6. private PersonPrototypeManager(){}
  7. public static synchronized void put(String personId,Person person){
  8. personMap.put(personId,person);
  9. }
  10. public static synchronized void remove(String personId){
  11. personMap.remove(personId);
  12. }
  13. public static synchronized Person get(String personId){
  14. return personMap.get(personId);
  15. }
  16. }
  1. /**
  2. * 测试原型模式
  3. */
  4. public class PrototypeTest {
  5. @Test
  6. public void testClone() throws CloneNotSupportedException {
  7. //浅复制
  8. Person oldPerson = new Person("田小娥", 24, new Date());
  9. Person newPerson = (Person) oldPerson.clone();
  10. System.out.println(newPerson);
  11. System.out.println(oldPerson == newPerson);
  12. //注册到原型管理器中
  13. PersonPrototypeManager.put(newPerson.getName(),newPerson);
  14. System.out.println(PersonPrototypeManager.get(newPerson.getName()));
  15. }
  16. @Test
  17. public void testDeepClone() throws IOException, ClassNotFoundException {
  18. //深复制
  19. Person oldPerson = new Person("田小娥", 24, new Date());
  20. Person newPerson = (Person) oldPerson.deepClone();
  21. System.out.println(newPerson);
  22. System.out.println(oldPerson == newPerson);
  23. //注册到原型管理器中
  24. PersonPrototypeManager.put(newPerson.getName(),newPerson);
  25. System.out.println(PersonPrototypeManager.get(newPerson.getName()));
  26. }
  27. }

吹牛:原型模式可以在不改变接口的情况下,动态的改变实现类对象。缺点是对于不支持序列化的类如Thread对象和Socket对象无能为力;深复制时可能会出现循环引用,导致程序奔溃。

后记

  感谢java-my-file,撰写本文参考了其文章《JAVA与模式》之原型模式
  转载时,请注明出处,这是人格的一种体现。
  https://www.zybuluo.com/BertLee/note/843705
  能力有限,如有纰漏,请在评论区指出,老朽虽一把年纪,必当感激涕零,泪如雨下。若有满嘴喷粪撕逼者,一律拉黑、举报,并移交阎王爷处理。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注