设计模式之原型模式 PrototypePattern

一、模式定义

通过复制现有实例来创建新的实例,无需知道相应类的信息。

二、模式使用场景

  • 类初始化需要消耗非常多的资源。
  • 通过new产生一个对象需要非常繁琐的数据准备或访问权限。
  • 提供给其他对象访问,而且各个调用者可能需要修改其值时。

三、代码实现

public class WordDocument implements Cloneable {
    private String mText;
    private ArrayList mImages = new ArrayList<>();
    public WordDocument() {
    }
    @Override
    public WordDocument clone() {
        try {
            WordDocument doc = (WordDocument) super.clone();
            // 浅拷贝,只是单纯的只想了内存引用
            doc.mText = this.mText;
            doc.mImages = this.mImages;
            // 深拷贝,操作副本时不会影响原始对象
            doc.mImages = (ArrayList) this.mImages.clone();
            return doc;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    //省略构造函数...
}

四、深拷贝和浅拷贝的区别

  • 深拷贝:拷贝时创建一个新的对象,并且所有属性都是新对象(指向新的内存地址)。对复制后的对象进行修改,不会影响原来对象的值。
  • 浅拷贝:拷贝时创建一个新的对象,对象中的属性如果是基本数据类型会新创建的对象,但是属性是引用类型不会创建新的对象,而是使用与之前的对象指向同一个内存地址。对复制后的对象进行修改,仍然会影响原来对象的值。

五、Android源码分析

Android中的Intent就实现了Cloneable接口,但是clone()方法中却是通过new来创建对象的。

public class Intent implements Parcelable, Cloneable {
        //其他代码略
        @Override
        public Object clone() {
            //这里没有调用super.clone()来实现拷贝,而是直接通过new来创建
            return new Intent(this);
        }
        public Intent(Intent o) {
            this.mAction = o.mAction;
            this.mData = o.mData;
            this.mType = o.mType;
            this.mPackage = o.mPackage;
            this.mComponent = o.mComponent;
            this.mFlags = o.mFlags;
            this.mContentUserHint = o.mContentUserHint;
            if (o.mCategories != null) {
                this.mCategories = new ArraySet(o.mCategories);
            }
            if (o.mExtras != null) {
                this.mExtras = new Bundle(o.mExtras);
            }
            if (o.mSourceBounds != null) {
                this.mSourceBounds = new Rect(o.mSourceBounds);
            }
            if (o.mSelector != null) {
                this.mSelector = new Intent(o.mSelector);
            }
            if (o.mClipData != null) {
                this.mClipData = new ClipData(o.mClipData);
            }
        }
    }

在《 Android 源码设计模式解析与实战》中讲到,在 Intent 的 clone 方法中并没有调用 super.clone() 方法来实现对象拷贝,而是调用 new Intent() 的原因是:使用 clone 和 new 需要根据构造对象的成本来决定,如果对象的构造成本或者构造较为麻烦的时候使用 clone 函数效率较高,否则可以使用 new 的形式。

六、模式优缺点

  • 优点

    1. 原型模式是在内存中二进制流的拷贝,要比直接new一个对象性能好,特别是产生大量对象时。
    2. 隐藏制造新实例的重要性。
    3. 在重复创建相似对象的时候可以用。
  • 缺点

    1. 直接在内存中拷贝,构造函数是不会执行的,应该注意这个潜在问题。
    2. 每个类都必须配备一个克隆方法。
    3. 深拷贝会较为复杂。

七、总结

原型模式本质上就是对象拷贝,使用原型模式可以解决构造复杂对象的资源消耗问题,能够在某些场景下提升创建对象的效率。还有一个重要用途就是保护性拷贝,也就是某个对象对外可能是只读的,为了防止外部对这个只读对象进行修改,通常可以通过返回一个对象拷贝的形式实现只读的限制。另外需要区别浅拷贝和深拷贝,它们之间容易出现问题,

你可能感兴趣的:(设计模式之原型模式 PrototypePattern)