<<设计模式之禅(第二版)>>——第十三章 原型模式

定义:
  • 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
通用类图:
<<设计模式之禅(第二版)>>——第十三章 原型模式_第1张图片
原型模式通用类图
/*
 * 实现Cloneable接口,复习父类中的clone方法
 * */
public class Prototype implements Cloneable {
  @Override
  public Prototype clone(){
    // TODO Auto-generated method stub
    Prototype prototype = null;
    try {
        prototype = (Prototype) super.clone();
    } catch (Exception e) {
        // TODO Auto-generated catch block
        // 相关的异常处理
        e.printStackTrace();
    }
    return prototype;
  }

}
原型模式的优点(通常是和工厂方法模式一起出现,通过clone的方法创建一个对象,然后由工厂方法提供给调用者):
  • 性能优良,原型模式是对内存中二进制流的拷贝,要比直接new一个对象的性能好很多
  • 逃避构造函数的约束,直接在内存中拷贝,构造函数是不会执行的。
原型模式的使用场景:
  • 资源优化场景,类初始化需要消耗非常多的资源,数据、硬件资源等
  • 性能和安全要求的场景,通过new产生一个对象需要非常繁琐的数据准备或访问权限
  • 一个对象多个修改者
原型模式的注意事项
  • 构造函数不会被执行(new 会执行构造函数中的方法,通过clone则不会执行构造函数中的方法)
  • 浅拷贝和深拷贝
  /*
  * 浅拷贝代码
  * */
  public class ThingSimple implements Cloneable {
    // 定义一个私有变量
    private ArrayList arrayList = new ArrayList();

    @Override
    public ThingSimple clone() {
    // TODO Auto-generated method stub
    ThingSimple thingSimple = null;
    try {
        thingSimple = (ThingSimple) super.clone();
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return thingSimple;
    }

    public void setValue(String value) {
    this.arrayList.add(value);
    }

    public ArrayList getValue() {

    return this.arrayList;
    }
  }
  public class ThingDeep implements Cloneable {
    // 定义一个私有变量
    private ArrayList arrayList = new ArrayList();

    @Override
    public ThingDeep clone() {
    // TODO Auto-generated method stub
    ThingDeep thingDeep = null;
    try {
        thingDeep = (ThingDeep) super.clone();
        thingDeep.arrayList = (ArrayList) this.arrayList.clone();
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return thingDeep;
    }

    public void setValue(String value) {
    this.arrayList.add(value);
    }

    public ArrayList getValue() {

    return this.arrayList;
    }

  }

  public class Client {
    public static void main(String[] args) {
      // 测试浅拷贝
      ThingSimple thingSimple = new ThingSimple();
      thingSimple.setValue("1");

      ThingSimple copySimple = thingSimple.clone();
      copySimple.setValue("2");
      System.out.println("原数据-->" + thingSimple.getValue());
      System.out.println("拷贝数据-->" + copySimple.getValue());
      System.out.println(">>>>>>>>>>>>>>>");
      // 测试深拷贝
      ThingDeep thingDeep = new ThingDeep();
      thingDeep.setValue("3");
      ThingDeep copyDeep = thingDeep.clone();
      copyDeep.setValue("4");
      System.out.println("原数据-->" + thingDeep.getValue());
      System.out.println("拷贝数据-->" + copyDeep.getValue());
    }
  }


 原数据-->[1, 2]
 拷贝数据-->[1, 2]
 >>>>>>>>>>>>>>>
 原数据-->[3]
 拷贝数据-->[3, 4]
 解析:java做了一个偷懒的拷贝动作,Object类提供的方法clone只是拷贝对象本身,其对象内部的数组、
      引用对象等都不拷贝,还是指向原生对象的内部元素地址,这种拷贝叫做浅拷贝,
      多个对象共享一个变量,是一种非常不安全的方式。内部的数组和引用对象不拷贝,
      其他原始类型,比如int、long、char等都会被拷贝,但是对于string类型,
      java希望你认为它是基本类型,它是没有clone方法的,并且处理机制也比较特殊,
      通过字符串池(stringpool)在需要的时候才在内存中创建新的字符串。
 注:在使用原型模式的时候,引用的成员变量必须满足,一是类的成员变量,
    不是方法内变量,二必须是可变的引用对象,而不是一个原始的类型或不可变对象。
    对于深拷贝不能使用final进行修饰,因为要重新赋值,对于浅拷贝因为指向的是
    内存中同一个地址,所以无影响。

你可能感兴趣的:(<<设计模式之禅(第二版)>>——第十三章 原型模式)