原型模式

作者: YoungerDev | 来源:发表于2018-04-02 18:15 被阅读95次

    Android进阶之设计模式

    原型模式

    定义: 用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象.

    使用场景:

    1. 类初始化需要消耗非常多的资源,这个资源包括数据,硬件资源等,通过原型拷贝避免这些消耗.
    2. 通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,这时可以用原型模型.
    3. 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用,保护性拷贝.

    需要注意的是,通过实现 Cloneable 接口的原型模式在调用clone 函数构造实例时并不一定比通过 new 操作速度快,只有当通过 new 构造对象较为耗时或者成本较高时,通过 clone 方法才能够获得效率上的提升.

    优点: 原型模式在内存中二进制流的拷贝,要比 new 一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点.

    缺点: 这既是它的优点也是缺点.直接在内存中拷贝,构造函数是不会执行的,在实际开发中应该注意这个潜在问题,优点就是减少了约束,缺点也是减少了约束.

    下面用的例子来说明问题:

    
    
    public class WordDocument implements Cloneable {
    
        //文本
        private String mText;
    
        //图片名称表
        private ArrayList<String> mImages = new ArrayList<String>();
    
        public WordDocument() {
            System.out.println("=======WordDocument构造函数=======");
        }
    
        @Override
        public WordDocument clone() {
    
            try {
                WordDocument document = (WordDocument) super.clone();
                document.mText = this.mText;
                document.mImages = this.mImages;
                return document;
    
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
    
            return null;
        }
    
        public String getmText() {
            return mText;
        }
    
        public void setText(String mText) {
            this.mText = mText;
        }
    
        public ArrayList<String> getmImages() {
            return mImages;
        }
    
        public void addImages(String mImages) {
            this.mImages.add(mImages) ;
        }
    
        public void showDocument(){
    
            System.out.println("--------- Word Content Start -----------");
            System.out.println("Text :"+mText);
            System.out.println("Images list :");
            for (String imName : mImages){
                System.out.println("image name :"+imName);
            }
            System.out.println("============= word content end =======");
        }
    }
    
    

    Client 端使用

     public static void main(String[] args) {
     
    
            //1. 构建文档对象
            WordDocument originDoc = new WordDocument();
    
            //2. 编辑文档,添加图片等.
            originDoc.setText("这是一篇文档");
    
            originDoc.addImages("图片1");
            originDoc.addImages("图片2");
            originDoc.addImages("图片3");
            originDoc.showDocument();
    
            WordDocument doc2 = originDoc.clone();
            doc2.showDocument();
            doc2.setText("这是修改过的Doc2文本");
            doc2.showDocument();
    
            originDoc.showDocument();
    
    
        }
        
    

    打印出来的结果是:

    =======WordDocument构造函数=======
    --------- Word Content Start -----------
    Text :这是一篇文档
    Images list :
    image name :图片1
    image name :图片2
    image name :图片3
    ============= word content end =======
    --------- Word Content Start -----------
    Text :这是一篇文档
    Images list :
    image name :图片1
    image name :图片2
    image name :图片3
    ============= word content end =======
    --------- Word Content Start -----------
    Text :这是修改过的Doc2文本
    Images list :
    image name :图片1
    image name :图片2
    image name :图片3
    ============= word content end =======
    --------- Word Content Start -----------
    Text :这是一篇文档
    Images list :
    image name :图片1
    image name :图片2
    image name :图片3
    ============= word content end =======
    
    

    以上是属于浅拷贝,这份拷贝实际上并不是将原始文档的所有字段都重新构造了一份,而是副本字段引用原始文档的字段,
    当 A 引用 B 就是说两个对象指向同一个地址,当修改 A 时 B 也会改变,B 修改时 A 同样也会改变

    比如,将 main 函数修改为 现在这样样子,会发生什么呢?

    
     public static void main(String[] args) {
     
       //1. 构建文档对象
            WordDocument originDoc = new WordDocument();
    
            //2. 编辑文档,添加图片等.
            originDoc.setText("这是一篇文档");
    
            originDoc.addImages("图片1");
            originDoc.addImages("图片2");
            originDoc.addImages("图片3");
            originDoc.showDocument();
    
            WordDocument doc2 = originDoc.clone();
            doc2.showDocument();
            doc2.setText("这是修改过的Doc2文本");
            //区别 就在增加一个图片4
            doc2.addImages("图片4");
            doc2.showDocument();
    
            originDoc.showDocument();
    
        }
        
    

    现在 打印出的结果是:

    
    =======WordDocument构造函数=======
    --------- Word Content Start -----------
    Text :这是一篇文档
    Images list :
    image name :图片1
    image name :图片2
    image name :图片3
    ============= word content end =======
    --------- Word Content Start -----------
    Text :这是一篇文档
    Images list :
    image name :图片1
    image name :图片2
    image name :图片3
    ============= word content end =======
    --------- Word Content Start -----------
    Text :这是修改过的Doc2文本
    Images list :
    image name :图片1
    image name :图片2
    image name :图片3
    image name :图片4
    ============= word content end =======
    --------- Word Content Start -----------
    Text :这是一篇文档
    Images list :
    image name :图片1
    image name :图片2
    image name :图片3
    image name :图片4
    ============= word content end =======
    
    

    可以看到的是 最后面, 拷贝的,原始的都有了 图片4 , 这就是因为以上就浅拷贝,引用类型的 doc2 的 images 只是单纯地指向了 this.images 引用,并没有重新构造一个 image 对象, 然后将原始文档的图片添加到新的 images 对象中, 这就导致了 doc2 中的 images 与原始文档中的是同一个对象,因此修改其中一个文档中的图片,另一个文档也会受影响.

    要想解决这个问题呢,就需要采用深拷贝,而不是单纯引用的形式.clone 方法的修改如下:

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

    现在打印出的结果是:

    
    =======WordDocument构造函数=======
    --------- Word Content Start -----------
    Text :这是一篇文档
    Images list :
    image name :图片1
    image name :图片2
    image name :图片3
    ============= word content end =======
    --------- Word Content Start -----------
    Text :这是一篇文档
    Images list :
    image name :图片1
    image name :图片2
    image name :图片3
    ============= word content end =======
    --------- Word Content Start -----------
    Text :这是修改过的Doc2文本
    Images list :
    image name :图片1
    image name :图片2
    image name :图片3
    image name :图片4
    ============= word content end =======
    --------- Word Content Start -----------
    Text :这是一篇文档
    Images list :
    image name :图片1
    image name :图片2
    image name :图片3
    ============= word content end =======
    
    
    结论:可以看出 构造方法的确就执行了一次,拷贝后的修改,并不会修改原来的内容. 在实际开发中尽量使用深拷贝.

    相关文章

      网友评论

        本文标题:原型模式

        本文链接:https://www.haomeiwen.com/subject/xbsxhftx.html