设计模式系列--原型模式

定义

原型模式属于对象的创建模式。通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象。这就是原型模式的用意。

原型模式的结构

原型模式要求对象实现一个可以“克隆”自身的接口,这样就可以通过复制一个实例对象本身来创建一个新的实例。这样一来,通过原型实例创建新的对象,就不再需要关心这个实例本身的类型,只要实现了克隆自身的方法,就可以通过这个方法来获取新的对象,而无须再去通过new来创建。

定必比较抽象,下面通过一个例子,来介绍原型模式;
首先我们定义一个Person类

public class Person{
    private String name;
    private int age;
    private double height;
    private double weight;

    public Person(){
        
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height +
                ", weight=" + weight +
                '}';
    }
}

要实现原型模式,只需要按照下面的几个步骤去实现即可。

  • 实现Cloneable接口
public class Person implements Cloneable{

}
  • 重写Object的clone方法
@Override
public Object clone(){
    return null;
}
  • 实现clone方法中的拷贝逻辑
@Override
public Object clone(){
    Person person=null;
    try {
        person=(Person)super.clone();
        person.name=this.name;
        person.weight=this.weight;
        person.height=this.height;
        person.age=this.age;
    } catch (CloneNotSupportedException e) {
        e.printStackTrace();
    }
    return person;
}

测试一下

public class Main {
    public static void main(String [] args){
        Person p=new Person();
        p.setAge(18);
        p.setName("张三");
        p.setHeight(178);
        p.setWeight(65);
        System.out.println(p);

        Person p1= (Person) p.clone();
        System.out.println(p1);

        p1.setName("李四");
        System.out.println(p);
        System.out.println(p1);
    }
}

输出结果如下:

Person{name=’张三’, age=18, height=178.0, weight=65.0}
Person{name=’张三’, age=18, height=178.0, weight=65.0}
Person{name=’张三’, age=18, height=178.0, weight=65.0}
Person{name=’李四’, age=18, height=178.0, weight=65.0}

试想一下,两个不同的人,除了姓名不一样,其他三个属性都一样,用原型模式进行拷贝就会显得异常简单,这也是原型模式的应用场景之一。

一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用,即保护性拷贝。
但是假设Person类里还有一个属性叫兴趣爱好,是一个List集合,就像这样子

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

public ArrayList<String> getHobbies() {
    return hobbies;
}

public void setHobbies(ArrayList<String> hobbies) {
    this.hobbies = hobbies;
}

在进行拷贝的时候要格外注意,如果你直接按之前的代码那样拷贝

@Override
public Object clone(){
    Person person=null;
    try {
        person=(Person)super.clone();
        person.name=this.name;
        person.weight=this.weight;
        person.height=this.height;
        person.age=this.age;
//person.hobbies=this.hobbies 这种方式只进行了浅拷贝,也就是只拷贝了引用,最终两个对象指向的引用是同一个,一个发生变化另一个也会发生变换,显然解决方法就是使用深拷贝。
        //person.hobbies=this.hobbies;
person.hobbies=(ArrayList<String>)this.hobbies.clone();

    } catch (CloneNotSupportedException e) {
        e.printStackTrace();
    }
    return person;
}

其实有时候我们会更多的看到原型模式的另一种写法。

  • 在clone函数里调用构造函数,构造函数的入参是该类对象。
@Override
public Object clone(){
    return new Person(this);
}
  • 在构造函数中完成拷贝逻辑
public Person(Person person){
    this.name=person.name;
    this.weight=person.weight;
    this.height=person.height;
    this.age=person.age;
    this.hobbies= new ArrayList<String>(hobbies);
}

其实都差不多,只是写法不一样。
现在来挖挖android中的原型模式。
先看Bundle类,该类实现了Cloneable接口

public Object clone() {
    return new Bundle(this);
} 
public Bundle(Bundle b) {
    super(b);

    mHasFds = b.mHasFds;
    mFdsKnown = b.mFdsKnown;
}

然后是Intent类,该类也实现了Cloneable接口

@Override
public Object clone() {
    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<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与现有的一个Intent很多东西都是一样的,那我们就可以直接拷贝现有的Intent,再修改不同的地方,便可以直接使用。

Uri uri = Uri.parse("smsto:10086");    
Intent shareIntent = new Intent(Intent.ACTION_SENDTO, uri);    
shareIntent.putExtra("sms_body", "hello");    

Intent intent = (Intent)shareIntent.clone() ;
startActivity(intent);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,825评论 4 377
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,887评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,425评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,801评论 0 224
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,252评论 3 299
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,089评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,216评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 31,005评论 0 215
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,747评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,883评论 2 255
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,354评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,694评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,406评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,222评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,242评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,017评论 2 281

推荐阅读更多精彩内容