场景 如果一个对象,我们希望拷贝一个这个对象,就是弄出来这个类的另外一个实例,实例的属性跟之前的实例是一模一样的

1.常规

  1. package com.example.demo.pattern.prototype;
  2. /**
  3. * @author chenchao
  4. * @date 2021/11/9
  5. */
  6. public class WithoutPrototypePatternDemo {
  7. public static void main(String[] args) {
  8. // 手头有这么一个对象,需要进行拷贝
  9. Product product = new Product("测试产品", new Component("测试组件"));
  10. // 手动来拷贝
  11. Product copyProduct = new Product(product.getName(), product.getComponent());
  12. System.out.println(copyProduct);
  13. // 问题是什么?
  14. // 代码的拷贝逻辑,是每个要拷贝的调用方自己来实现的
  15. // 相同的拷贝逻辑会分散在很多不同的地方,如果拷贝逻辑改变了,多个调用的地方都要修改代码
  16. // 可维护性、可扩展性,很差
  17. }
  18. public static class Component {
  19. private String name;
  20. public Component(String name) {
  21. super();
  22. this.name = name;
  23. }
  24. public String getName() {
  25. return name;
  26. }
  27. public void setName(String name) {
  28. this.name = name;
  29. }
  30. @Override
  31. public String toString() {
  32. return "Component [name=" + name + "]";
  33. }
  34. }
  35. public static class Product {
  36. private String name;
  37. private Component component;
  38. public Product(String name, Component component) {
  39. super();
  40. this.name = name;
  41. this.component = component;
  42. }
  43. public String getName() {
  44. return name;
  45. }
  46. public void setName(String name) {
  47. this.name = name;
  48. }
  49. public Component getComponent() {
  50. return component;
  51. }
  52. public void setComponent(Component component) {
  53. this.component = component;
  54. }
  55. @Override
  56. public String toString() {
  57. return "Product [name=" + name + ", component=" + component + "]";
  58. }
  59. }
  60. }

2.原型模式

  1. package com.example.demo.pattern.prototype;
  2. /**
  3. * @author chenchao
  4. * @date 2021/11/9
  5. */
  6. public class PrototypePatternDemo {
  7. public static void main(String[] args) {
  8. try {
  9. Product product = new Product("测试产品", new Component("测试组件"));
  10. Product copyProduct = (Product) product.clone();
  11. System.out.println(copyProduct);
  12. } catch (Exception e) {
  13. e.printStackTrace();
  14. }
  15. // 原型模式,就是在要拷贝的类里实现一个clone()方法,自己拷贝自己
  16. // 拷贝的时候,就两个概念,浅拷贝,深拷贝
  17. // 很多地方要克隆这个对象,不要自己维护克隆的逻辑,即使克隆逻辑修改了,只要在clone()方法里面修改
  18. }
  19. public static class Component {
  20. private String name;
  21. public Component(String name) {
  22. super();
  23. this.name = name;
  24. }
  25. public String getName() {
  26. return name;
  27. }
  28. public void setName(String name) {
  29. this.name = name;
  30. }
  31. @Override
  32. public String toString() {
  33. return "Component [name=" + name + "]";
  34. }
  35. @Override
  36. protected Object clone() throws CloneNotSupportedException {
  37. return new Component(getName());
  38. }
  39. }
  40. public static class Product {
  41. private String name;
  42. private Component component;
  43. public Product(String name, Component component) {
  44. super();
  45. this.name = name;
  46. this.component = component;
  47. }
  48. public String getName() {
  49. return name;
  50. }
  51. public void setName(String name) {
  52. this.name = name;
  53. }
  54. public Component getComponent() {
  55. return component;
  56. }
  57. public void setComponent(Component component) {
  58. this.component = component;
  59. }
  60. @Override
  61. public String toString() {
  62. return "Product [name=" + name + ", component=" + component + "]";
  63. }
  64. @Override
  65. protected Object clone() throws CloneNotSupportedException {
  66. // 浅拷贝,就是我们现在的一个实现
  67. // 就是仅仅简单的对当前所有的变量进行一个拷贝
  68. // return new Product(getName(), getComponent());
  69. // 深考别,递归对自己引用的对象也进行拷贝
  70. return new Product(getName(), (Component)getComponent().clone());
  71. }
  72. }
  73. }

3.说明

原型模式,顾名思义,其实说白了,就是让一个对象可以自己拷贝自己,对象把自己当成一个原型,然后提供一个方法出去,外部要一个对象的克隆和拷贝,直接就copy一份就可以了,但是这里要记住深拷贝和浅拷贝的区别

因为一个对象可能还持有别的对象的引用,浅拷贝就是不管引用的其他对象了;深拷贝就是将引用的对象也一起拷贝一份;一般原型模式都是要支持深拷贝的

而且其实一般实现原型模式的时候,直接是通过覆盖Object类的clone()方法即可,在里面实现自己的拷贝逻辑就可以了

使用原型模式比较好的一点,就是如果别人要拷贝你的对象,不需要调用方自己实现拷贝逻辑,将拷贝逻辑放在对象自己身体里就可以了,对外面调用都是透明的