原型模式——使程序运行更高效

(《设计模式解析与实战》读书笔记)

一、定义
用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象;
二、使用场景
(1)类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等,通过原型拷贝避免这些消耗;
(2)通过new产生一个对象需要非常繁琐的数据准备或访问权限,这时可使用原型模式;
(3)一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用,即保护性拷贝。
三、简单示例
修改一份文档,我们一般不会直接修改“原型”,而是拷贝一份副本进行修改。

/**
 * 文档是具体的原型类;Cloneable是接口,声明具备clone能力
 */
public class WordDocument implements Cloneable {
    // 文本
    private String mText;
    // 图片列表
    private ArrayList<String> mImages = new ArrayList<>();

    public WordDocument() {
        System.out.println("------我是WordDocument构造函数-------");
    }

    @Override
    protected WordDocument clone() {
        try {
            WordDocument doc = (WordDocument) super.clone();
            doc.mText = this.mText;
            doc.mImages = this.mImages;
            return doc;
        } catch (Exception e) {
        }
        return null;
    }

    public String getmText() {
        return mText;
    }

    public void setmText(String mText) {
        this.mText = mText;
    }

    public ArrayList<String> getmImages() {
        return mImages;
    }

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

    /**
     * 打印文档内容
     */
    public void showDocument() {
        System.out.println("-----开始打印-----");
        System.out.println("Text :" + mText);
        System.out.println("Images List : ");
        for (String imgName : mImages) {
            System.out.println("image name : " + imgName);
        }
        System.out.println("-----打印结束-----");
    }

}
public class Client {
    public static void main(String[] args) {
        // 1、构建文档对象
        WordDocument document = new WordDocument();
        // 2、修改文档
        document.setmText("这是一篇文档");
        document.addImages("图片1");
        document.addImages("图片2");
        document.showDocument();

        // 以原始文档为原型,拷贝一份副本
        WordDocument document2 = document.clone();
        System.out.println("这是未修改的副本");
        document2.showDocument();

        // 修改文档副本,不会影响原始文档
        document2.setmText("这是修改后的副本");
        document2.showDocument();

        // 验证原始文档是否被修改
        document.showDocument();
    }
}

输出后的结果:

这里写图片描述
这里写图片描述
可以看出在副本上修改不会影响到原型。并且通过clone拷贝对象时并不会执行构造函数。
修改Client代码:
// 修改文档副本

        document2.setmText("这是修改后的副本");
        document2.addImages("副本图片.jpg");
        document2.showDocument();

运行结果:
这里写图片描述
会发现原型被修改了。原因是上述方法只是浅拷贝,document2的mImages只是单纯的指向了this.mImages引用,并没有重新构造一个mImages对象。
运用深拷贝可解决这个问题,在拷贝时,对于引用型的字段也要采用拷贝的形式,而不是引用的形式。
修改clone()方法:

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

运行后发现副本添加图片并不会影响到原型。
这里写图片描述
所以在使用该模式时尽量使用深拷贝,避免操作副本时影响原始对象的问题。

四、优缺点
优点:
运行模式是在内存中二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好的体现其优点。
缺点:
直接在内存中拷贝,构造函数是不会执行的,在实际开发中应该注意这个潜在的问题。优点是减少了约束,缺点也是减少了约束,需要我们在实际应用中考虑。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章