设计模式与Android原型模式——复制中心走出来的克隆人

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式与Android原型模式——复制中心走出来的克隆人相关的知识,希望对你有一定的参考价值。

什么是原型模式

 

所谓原型模式,就是用原型实例来指定创建对象的种类,并通过复制这些原型创建新的对象的设计模式。原型模式一般用于创建复杂的或者构建耗时的实例,或者用于只读对象的修改。

 

原型模式的实现方式

 

(1)浅拷贝

当代的每个程序员小时候都玩过《尤里的复仇》这款游戏,游戏中的“尤里”阵营有个兵种叫“尤里复制人”,每个尤里复制人都和尤里长得一模一样,除了没有坐骑之外。

public class Yuri{

    private String name = "Yuri";

    private ArrayList<String> words = new ArrayList<>();

    public void setName(String name) {
        this.name = name;
    }

    public void addWord(String word){
        this.words.add(word);
    }

    @Override
    protected Yuri clone(){
        try{
            return (Yuri) super.clone();
        }catch (CloneNotSupportedException e){
            return null;
        }
    }

    @Override
    public String toString() {
        return "Yuri{" +
                "name=‘" + name + \‘+
                ", words=" + words.toString() +
                ‘}‘;
    }
}

 

如上,重写了clone()方法。在执行如下代码时:

Yuri yuri = new Yuri();
yuri.setName("Yuri");
yuri.addWord("My name is Yuri");
yuri.addWord("You mind is clear");

Yuri yuri_copyer = yuri.clone();
yuri.setName("Yuri‘s copyer");

yuri.addWord("I‘m not the only one true Yuri");



Log.e("yuri_copyer",yuri_copyer.toString());
Log.e("yuri",yuri.toString());

会惊奇地发现两行Log一模一样,这是因为这种原型模式的实现方式只拷贝其引用,换句话说就是并没有将原型对象中的所有字段都重新构造一份,只是用复制对象的字段引用原型对象中的字段,因此被称为“浅拷贝”或“影子拷贝”。

 

(2)深拷贝

我们把上文的clone()方法修改一下:

@Override
protected Yuri clone(){
    try{
        Yuri copyer = (Yuri) super.clone();
        copyer.name = this.name;
        copyer.words = (ArrayList<String>)this.words.clone();
        return copyer;
    }catch (CloneNotSupportedException e){
        return null;
    }
}

 

如上,这种实现方式调用了的clone()方法,这样可以保证副本被修改时不影响原始对象,因此被称为“深拷贝”,又叫做“保护性拷贝”。

 

android源码中的原型模式

 

1)ArrayList

严格来说ArrayList并不算是Android源码中的类,但应该是Android开发者最常用的类,ArrayList的clone()代码如下:

/**
 * Returns a shallow copy of this <tt>ArrayList</tt> instance.  (The
 * elements themselves are not copied.)
 *
 * @return a clone of this <tt>ArrayList</tt> instance
 */
public Object clone() {
    try {
        ArrayList<?> v = (ArrayList<?>) super.clone();
        v.elementData = Arrays.copyOf(elementData, size);
        v.modCount = 0;
        return v;
    } catch (CloneNotSupportedException e) {
        // this shouldn‘t happen, since we are Cloneable
        throw new InternalError(e);
    }
}

 

大家可以看到size并没有被clone,因为size是基础类型而不是引用类型,所以不需要clone。细心的读者可以看到注释里面的“shallow copy”,但这实际上是一个典型的深拷贝。

 

(3)Intent

Android系统加入Intent机制的意义在于大大降低了Android四大组件之间的耦合度。Intent的clone()代码如下:

@Override
public Object clone() {
    return new Intent(this);
}

 

/**
 * Copy constructor.
 */
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<String>(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);
    }
}

 

Intent的clone()内部并没有调用super.clone(),而是调用了new Intent(this)。

 

Android开发中如何利用原型模式

 

(1)Object的clone()方法直接操作二进制流,效率非常高。在对象的初始化要消耗非常多的资源时,或者用new来实例化一个对象时需要非常繁琐的数据准备或访问权限时,可以使用原型模式提高效率、避免消耗资源。

 

2)对深拷贝生成的副本进行修改不会影响原始对象。当一个对象会被不同对象用不同方式修改时,可以用原型模式产生副本供调用者使用。

 

需要注意的几个问题

 

(1)原型模式在clone()的时候不会重新执行构造函数,可能会出现问题。

 

(2)在某些对象构造非常简单的情况下,比如上文提到的Intent,重新new一个比clone()快,因此不要滥用原型模式


本文出自 “玖哥的书房” 博客,请务必保留此出处http://dongfeng9ge.blog.51cto.com/9191243/1972482

以上是关于设计模式与Android原型模式——复制中心走出来的克隆人的主要内容,如果未能解决你的问题,请参考以下文章

C#设计模式之原型模式

设计模式——10.原型模式

Android设计模式- 原型模式

设计模式——创建型模式之原型模式

《Android源码设计模式》--原型模式

PHP设计模式—原型模式