Android设计模式之原型模式

原型模式

1.定义:

用原型实例指定创建对象的种类,并通过copy这些原型创建新的对象。

2.使用场景:

  • 类初始化需要消耗非常多的资源,这个资源包括数据、硬件资源等,通过原型copy避免了这些消耗;
  • 通过new产生一个对象需要非常繁琐的数据准备或访问权限,这时可以使用原型模式;
  • 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式copy多个对象供调用者使用,即保护性copy。
    注意:
    1.通过实现Cloneable接口的原型模式再调用clone函数构造实例时,并不一定比通过new操作效速度快,只有当通过new构造对象较为耗时或成本较高时,通过clone方法才能获得效率上的提升。因此,在使用Cloneable时需要考虑构建对象的成本以及一些效率上的测试。
    2.实现原型模式不一定非要实现Cloneable接口,也有其他的实现方式。

3.UML图

4.详解:

原型模式是一个创建型模式,‘原型’二字表明该模式应该有一个样板实例,提供给用户访问copy。用户从这个样板对象中复制出一个内部属性一致的对象的过程,称为克隆。被复制的样板对象就是‘原型’。原型模式多用于创建复杂的或构造耗时的实例,因为这些情况下,复制一个已经存在的实例可使程序运行效率更高。
下面用代码举例阐述:

public static class WordDocument implements Cloneable {
        private String text;
        private ArrayList<String> images = new ArrayList<>();

        public WordDocument() {
            System.out.println("constructor start");
        }

        @Override
        protected WordDocument clone() {
            try {
                WordDocument doc = (WordDocument) super.clone();
                doc.text = text;
                doc.images = images;//浅拷贝
                return doc;
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
                return null;
            }
        }

        public String getText() {
            return text;
        }

        public void setText(String text) {
            this.text = text;
        }

        public List<String> getImages() {
            return images;
        }

        public void addImage(String img) {
            images.add(img);
        }

        public void showDocument() {
            System.out.println("text:" + text);
            System.out.print("images:");
            for (int i = 0; i < images.size(); i++) {
                if (i == images.size() - 1) {
                    System.out.print(images.get(i) + "\n");
                } else {
                    System.out.print(images.get(i) + ",");
                }
            }
        }
    }

测试代码:

public static void main(String[] args) {
        WordDocument originDoc = new WordDocument();
        originDoc.setText("原文档text");
        originDoc.addImage("img1");
        originDoc.addImage("img2");
        originDoc.addImage("img3");
        originDoc.showDocument();
        System.out.println("=========================");

        WordDocument newDoc = originDoc.clone();
        newDoc.showDocument();
        System.out.println("=========================");

        newDoc.setText("修改后的text");
        newDoc.addImage("img4");
        newDoc.showDocument();

        System.out.println("=========================");
        originDoc.showDocument();
        /**
         * 输出结果:
         constructor start
         text:原文档text
         images:img1,img2,img3
         =========================
         text:原文档text
         images:img1,img2,img3
         =========================
         text:修改后的text
         images:img1,img2,img3,img4
         =========================
         text:原文档text
         images:img1,img2,img3,img4
         */
    }

这里的WordDocument 就是所谓的‘原型’,它里面有文字描述与图片url。现在用户需要重新编辑该文档,又想不破坏原文档,于是用户需要复制一份原文档,在拷贝文档上编辑,详细过程见测试代码。
从上面的测试结果可以得出如下结论:

  • 通过clone 拷贝对象时,并不会执行构造函数,因此,如果在构造函数中需要初始化操作的类型,在使用Cloneable实现拷贝时,需注意构造函数不会执行的问题。
  • 副文档修改了文本内容,原文档内容不受影响,这样保证了原文档的安全性;
  • 但是,细心的你也许发现了,在副文档中添加img4,原文档也会有img4。说好的安全呢?瞬间被打脸,有木有?其实这个例子是浅拷贝(也称为‘影子拷贝’),这份拷贝并不是将原始文档的所有字段都重构了一份,而是副文档的字段引用了原始文档的字段,即原文档与副文档的字段images其实指向同一个地址,于是才会出现上述情况。那么这种情况该如何规避?答案是深拷贝!即在拷贝对象时,对于引用型的字段也采用拷贝的形式,而不是上面的单纯引用的方式。
    下面修改clone方法:doc.images = (ArrayList<String>) images.clone(),即深拷贝。
    @Override
        protected WordDocument clone() {
            try {
                WordDocument doc = (WordDocument) super.clone();
                doc.text = text;
                doc.images = (ArrayList<String>) images.clone();//深拷贝
                return doc;
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
                return null;
            }
        }

测试代码不变,但是输出的结果却变了,如下:

        /**
         * 输出结果:
         constructor start
         text:原文档text
         images:img1,img2,img3
         =========================
         text:原文档text
         images:img1,img2,img3
         =========================
         text:修改后的text
         images:img1,img2,img3,img4
         =========================
         text:原文档text
         images:img1,img2,img3
         */

修改了副文档的images,原文档也没有改变,很安全了。
原型模式是非常简单的模式,它的核心问题就是对原始对象进行拷贝,在这个模式的使用过程中需要注意的一点就是深、浅拷贝的问题。在实际开发过程中,为了减少错误,尽量使用深拷贝原型模式,避免操作副本对象时,影响了原始对象的属性

5.代码托管地址

原型模式

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

推荐阅读更多精彩内容