参考:1.《图解设计模式》 https://www.cnblogs.com/xuekyo/archive/2012/07/12/2587730.html java的浅克隆和深克隆:https://www.cnblogs.com/betterboyz/p/9356190.html Spring中的原型模式: https://www.jianshu.com/p/611be5eb42a1

模式定义

  • 创建对象的种类,并且通过拷贝这些原型创建新的对象;
  • Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节
  • 例如仪器数据采集器的共同初始化工作可在原型类对象中完成,随后将其克隆出PDF文件数据采集器对象和Excel文件数据采集器对象,并为两对象属性做后续的扩展,免去了公共属性的初始化工作。

    模式原理

  • 通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。

模式好处

  • 每次NEW一个对象,都需要执行一次构造函数,如果构造函数时间长,那么多次执行初始化的效率大大降低了。一般在初始化信息不变化的情况下,克隆是最好的方法。这既隐藏了对象创造的细节,又对性能是大大的提升。

    模式适合场景

  • 对象种类繁多,无法将其整合到一个类中,如果要这些对象分别作为一个类,则需要编写很多类文件;

  • 生成实例的过程太复杂,难以根据类来生成实例;
  • 想要让生成实例的框架依赖具体的类,这时不能指定类名来生成实例,而是事先“注册”一个“原型”实例,然后通过复制该实例来生成新的实例。

    Spring里的Prototype模式

  • 原型bean的创建

    1. protected <T> T doGetBean(
    2. final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
    3. throws BeansException {
    4. final String beanName = transformedBeanName(name);
    5. Object bean;
    6. // Eagerly check singleton cache for manually registered singletons.
    7. Object sharedInstance = getSingleton(beanName);
    8. if (sharedInstance != null && args == null) {
    9. ...
    10. }
    11. else {
    12. ...
    13. try {
    14. ...
    15. // Create bean instance.
    16. if (mbd.isSingleton()) {
    17. ...
    18. }
    19. //创建原型bean
    20. else if (mbd.isPrototype()) {
    21. // It's a prototype -> create a new instance.
    22. Object prototypeInstance = null;
    23. try {
    24. beforePrototypeCreation(beanName);
    25. prototypeInstance = createBean(beanName, mbd, args);
    26. }
    27. finally {
    28. afterPrototypeCreation(beanName);
    29. }
    30. bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
    31. }
    32. else {
    33. ...
    34. }
    35. }
    36. catch (BeansException ex) {
    37. cleanupAfterBeanCreationFailure(beanName);
    38. throw ex;
    39. }
    40. }
    41. ...
    42. return (T) bean;
    43. }

代码示例

UNL类图如下
Prototype模式_UML.png

  1. /**
  2. * @Author:ling
  3. * @Date:2020/4/30 21:08
  4. * @Version:1.0
  5. */
  6. public class Manager {
  7. private HashMap showCase = new HashMap();
  8. public void register (String name , Product proto) {
  9. showCase.put(name, proto) ;
  10. }
  11. public Product create (String protoname) {
  12. Product product = (Product) showCase.get(protoname);
  13. return product.createClone();
  14. }
  15. }
  1. public interface Product extends Cloneable{
  2. public abstract void use(String s) ;
  3. public abstract Product createClone() ;
  4. }
  1. /**
  2. * @Author:ling
  3. * @Date:2020/4/30 21:12
  4. * @Version:1.0
  5. */
  6. public class MessageBox implements Product {
  7. private char decochar;
  8. public MessageBox (char decochar) {
  9. this.decochar = decochar ;
  10. }
  11. @Override
  12. public void use(String s) {
  13. int length = s.getBytes().length;
  14. for (int i = 0 ; i < length + 4 ; i++) {
  15. System.out.print(decochar);
  16. }
  17. System.out.println("");
  18. System.out.println(decochar + "" + s + "" + decochar);
  19. for (int i = 0 ; i < length + 4 ; i++){
  20. System.out.print(decochar);
  21. }
  22. System.out.println("");
  23. }
  24. @Override
  25. public Product createClone() {
  26. Product p = null ;
  27. try {
  28. p = (Product) clone();
  29. } catch (CloneNotSupportedException e) {
  30. e.printStackTrace();
  31. }
  32. return p;
  33. }
  34. }
  1. /**
  2. * @Author:ling
  3. * @Date:2020/4/30 21:20
  4. * @Version:1.0
  5. */
  6. public class UnderlinePen implements Product {
  7. private char ulchar ;
  8. public UnderlinePen (char ulchar) {
  9. this.ulchar = ulchar;
  10. }
  11. @Override
  12. public void use(String s) {
  13. int length = s.getBytes().length;
  14. System.out.println("\"" + s + "\"");
  15. System.out.println(" ");
  16. for (int i = 0 ; i < length + 4 ; i++) {
  17. System.out.print(ulchar);
  18. }
  19. System.out.println("");
  20. }
  21. @Override
  22. public Product createClone() {
  23. Product p = null ;
  24. try {
  25. p = (Product) clone();
  26. } catch (CloneNotSupportedException e) {
  27. e.printStackTrace();
  28. }
  29. return p;
  30. }
  31. }
  1. /**
  2. * @Author:ling
  3. * @Date:2020/4/30 21:30
  4. * @Version:1.0
  5. */
  6. public class Main {
  7. public static void main(String[] args) {
  8. Manager manager = new Manager();
  9. UnderlinePen underlinePen = new UnderlinePen('~') ;
  10. MessageBox mbox = new MessageBox('*') ;
  11. MessageBox sbox = new MessageBox('/') ;
  12. manager.register("Strong message", underlinePen);
  13. manager.register("warning box", mbox);
  14. manager.register("slash box", sbox);
  15. Product p1 = manager.create("Strong message") ;
  16. p1.use("Hello world");
  17. Product p2 = manager.create("warning box");
  18. p2.use("Hello world");
  19. Product p3 = manager.create("slash box");
  20. p3.use("Hello world");
  21. }
  22. }

总结

  • 在上述代码中,Product接口和Manager类中代码中完全没有出现MessageBox类和UnderlinePen类的名字,这意味着我们可以独立修改Product和Manager,不受MessageBox类和UnderlinePen类的影响,一旦在类中使用了别的类名,就意味着该类与其他类紧密的耦合在了一起

扩展:Java的克隆方法

可参照笔记:https://www.yuque.com/woyubugtongzai/gb7au2/wby00g