文章目录

  • 1、原型模式介绍
  • 2、使用场景
  • 3、原型模式UML 类图
  • 4、原型模式的简单实现
  • 1)文件结构
  • 2)WordDocumentClass.java 文件
  • 3)ClientActivity.java 文件
  • 5、 浅拷贝 和 深拷贝


1、原型模式介绍

1)该模式有一个样板实例,用户从这个样板对象中复制一个内部属性一致的对象。
2)复制的实例就是我们的原型。
3)原型多用于创建复杂的或者构造耗时的实例。
4)复制一个已经存在的实例可以使程序更高效。

2、使用场景

1)初始化一个类需要消耗很多的资源,这个资源包括数据、硬件等,通过原型复制避免这些消耗。
2)初始化需要非常多的数据准备或者权限访问
3)一个对象可能提供给其他对象访问,而且各个调用都需要修改。

3、原型模式UML 类图

Androd  原型模式_原型模式

1)Client: 客户端用户
2)Prototype: 抽象类或接口,声明具备clone 能力
3)ConcretePrototype: 具体的原型类

4、原型模式的简单实现

就以文档拷贝为例来演示一下简单的原型模式的基本结构和思路。
1)首先创建 一个文档对象 WordDocument,这个文档包含 文字和图片
2)我们对内容编辑时先复制一个,将前文档备份,在文档副本上进行修改。

1)文件结构

Androd  原型模式_Android_02

2)WordDocumentClass.java 文件
package com.example.menglux.worddocument;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import java.util.ArrayList;
import java.util.List;

public class WordDocumentClass  implements  Cloneable {


    //文本
    private  String mText;
    //图片名列表
    private ArrayList<String> mImages = new ArrayList<String>();

    public WordDocumentClass() {
        System.out.println("```````WordDocument 构造函数········");
    }

    @Override
    protected WordDocumentClass clone() {
        try {

            WordDocumentClass doc = (WordDocumentClass) super.clone();
            doc.mText = this.mText;
            doc.mImages = this.mImages;
            return doc;
        } catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }


    public String getText() {
        return mText;
    }

    public void  setText(String mText) {
        this.mText = mText;
    }
    public List<String> getImages() {
        return mImages;
    }

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

    //打印文档内容

    public void showDocument() {
        System.out.println("``````Word Content Start````````");
        System.out.println("Text : " + mText);
        System.out.println("Images List: ");
        for (String imfName : mImages) {
            System.out.println(" image name: " + imfName);
        }

        System.out.println("``````````Word Contet End````````");
    }

}
3)ClientActivity.java 文件
package com.example.menglux.worddocument;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

/**
 * Created by menglux on 9/10/2018.
 */

public class ClientActivity  extends AppCompatActivity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_word_document);

        //构建文档对象
        WordDocumentClass originDoc = new WordDocumentClass();
        //编辑文档 添加图片
        originDoc.setText("这是一篇文档");
        originDoc.addImage("图爿1");
        originDoc.addImage("图片2");
        originDoc.addImage("图片3");
        originDoc.showDocument();


        //以原始文档为原型,拷贝一份副本
        WordDocumentClass doc2 = originDoc.clone();
        doc2.showDocument();

        //修改文档副本,不会影响原始文档
        doc2.setText("这是修改过的 Doc2 文档");
        doc2.showDocument();
    }
}

打印出来的log:

Androd  原型模式_原型模式_03

(1)我们可以看到,doc2是通过 originDoc.clone()创建的,并且doc2 第一次输出的和orginDoc是一样的。
(2)当我们修改了doc2 里的 文本之后, originDoc 的文本 并没有被改变。

5、 浅拷贝 和 深拷贝

1)上述原型 模式实际上 只是一个浅拷贝 ,也称为影子拷贝。
2)它并没有将所有字段重新构造一份,而是副本文档引用原始文档字段。

Androd  原型模式_原型模式_04

我们可以看到 A 引用B 就是说两个对象 指向同一个地址,当修改 A 时,B 也会改变。 B 修改时 A 同样 也会改变。

3) 我们 将 clientActivity .java 稍作修改

package com.example.menglux.worddocument;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

/**
 * Created by menglux on 9/10/2018.
 */

public class ClientActivity  extends AppCompatActivity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_word_document);

        //构建文档对象
        WordDocumentClass originDoc = new WordDocumentClass();
        //编辑文档 添加图片
        originDoc.setText("这是一篇文档");
        originDoc.addImage("图爿1");
        originDoc.addImage("图片2");
        originDoc.addImage("图片3");
        originDoc.showDocument();


        //以原始文档为原型,拷贝一份副本
        WordDocumentClass doc2 = originDoc.clone();
        doc2.showDocument();

        //修改文档副本,不会影响原始文档
        doc2.setText("这是修改过的 Doc2 文档");
        doc2.addImage("哈哈.jpg");
        doc2.showDocument();

        originDoc.showDocument();
    }
}

我们看 打印的log:

Androd  原型模式_java_05

我们可以看到最后两个文档的输出信息:
(1)对于 图片的 名称 是一样的,都添加了 哈哈.jpg
(2)上面的字符串 标题没有被改变,是因为 它并不是一个对象,是一个值类型。不是一个引用类型。
(3)引用对象的doc2只是单纯的指向this.image,并没有重新构造一个mImages对象。
(4)要解决这类修改 附件,原件不被修改,需要进行深度拷贝。

4)深度拷贝
我们 对 WordDocumentClass.java 的克隆函数进行稍微修改

@Override
    protected WordDocumentClass clone() {
        try {

            WordDocumentClass doc = (WordDocumentClass) super.clone();
            doc.mText = this.mText;
           // doc.mImages = this.mImages;
            // 对 mImages 对象也调用clone()函数, 进行深拷贝
            doc.mImages = (ArrayList<String>) this.mImages.clone();
            return doc;
        } catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

修改之后,doc.mImages 指向this.mImages的一份拷贝,而不是this.mImages 本身。这样在doc2添加图片时并不会影响originDoc。运行效果看log:

Androd  原型模式_Android_06


我们可以看到修改的doc2 出现了添加的 哈哈.jpg, origin 并没有出现添加的 哈哈.jpg

原型模式是比较简单的模式,适用于初始化对象消耗比较大的情况。
要考虑 深 浅 的拷贝问题。

文献参考:
Android 源码设计模式解析与实战 第二版
本人郑重声明,本博客所编文章、图片版权归权利人持有,本博只做学习交流分享所用,不做任何商业用途。访问者可將本博提供的內容或服务用于个人学习、研究或欣赏,不得用于商业使用。同時,访问者应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人的合法权利;如果用于商业用途,须征得相关权利人的书面授权。若文章、图片的原作者不愿意在此展示內容,请及时通知在下,將及时予以刪除。