Android设计模式Android技术知识Android开发

Android设计模式之(3)----原型模式

2017-08-16  本文已影响49人  Ch3r1sh

原型模式


用原型实例指定创建对象的,拷贝这些对象生成新的对象进行使用。

也可以直接进行new一个对象,但是当对象的构造复杂时,new的效率会很低,使用clone更好

new适用于简单的构造

clone适用于复杂的构造

应用场景

浅拷贝代码实现

<font color=#0099ff size=3 face="黑体">原型对象实现Cloneable接口</font>(默认是浅拷贝

class Prototype implements Cloneable {

    public Prototype clone() {
        Prototype prototype = null;
        try {
            prototype = (Prototype) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return prototype;
    }


}

原型对象具体的内容实现

class ConcretePrototype extends Prototype {

    public String name;
    public ArrayList<String> list = new ArrayList<>();

    public ConcretePrototype() {
        System.out.println("执行了ConcretePrototype构造函数");
    }

    @Override
    public String toString() {
        return "ConcretePrototype{" +
                "name='" + name + '\'' +
                ", list=" + list +
                '}';

    }


    public void show() {
        System.out.println("原型模式实现类");
    }
}   

使用方式

  ConcretePrototype cp = new ConcretePrototype();
        cp.name = "原始数据";
        for (int i = 0; i < 10; i++) {
            cp.list.add(i, String.valueOf(i));//填充数据
        }
        ConcretePrototype cloneConcretePrototype = (ConcretePrototype) cp.clone();//实现拷贝
        cloneConcretePrototype.name = "拷贝数据";
        System.out.println(cp.toString());
        System.out.println(cloneConcretePrototype.toString());
        

显示结果:

执行了ConcretePrototype构造函数
ConcretePrototype{name='原始数据', list=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}
ConcretePrototype{name='拷贝数据', list=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}

<font color=#0099ff size=3 face="黑体">原型对象不实现Cloneable接口</font>(默认是浅拷贝

其实就是把cloneable接口的内容手动实现一次

class ConcretePrototype2 {

    public String name;
    public ArrayList<String> list = new ArrayList<>();

    public ConcretePrototype2() {
        System.out.println("执行了ConcretePrototype2构造函数");
    }

    public ConcretePrototype2 clone() {
       //手动new对象进行赋值
        concretePrototype2 concretePrototype2 = new ConcretePrototype2();
        concretePrototype2.name = this.name;
        concretePrototype2.list = this.list;
        return concretePrototype2;
    }


    @Override
    public String toString() {
        return "ConcretePrototype2{" +
                "name='" + name + '\'' +
                ", list=" + list +
                '}';

    }


    public void show() {
        System.out.println("原型模式实现类");
    }
}

调用方式

 ConcretePrototype2 cp = new ConcretePrototype2();
        cp.name = "原始数据";
        for (int i = 0; i < 10; i++) {
            cp.list.add(i, String.valueOf(i));//填充数据
        }
        ConcretePrototype2 cloneConcretePrototype = (ConcretePrototype2) cp.clone();//实现拷贝
        cloneConcretePrototype.name = "拷贝数据";
        System.out.println(cp.toString());
        System.out.println(cloneConcretePrototype.toString());

显示结果

执行了ConcretePrototype2构造函数
执行了ConcretePrototype2构造函数
ConcretePrototype2{name='原始数据', list=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}
ConcretePrototype2{name='拷贝数据', list=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}

构造函数执行了两次,说明了cloneable接口的复制是不会执行2次构造的,直接new对象则会调用2次构造。

测试

修改复制后的数据

 ConcretePrototype2 cp = new ConcretePrototype2();
        cp.name = "原始数据";
        for (int i = 0; i < 10; i++) {
            cp.list.add(i, String.valueOf(i));//填充数据
        }
        ConcretePrototype2 cloneConcretePrototype = (ConcretePrototype2) cp.clone();//实现拷贝
        cloneConcretePrototype.name = "拷贝数据";
        cloneConcretePrototype.list.add("追加测试数据");
        System.out.println(cp.toString());
        System.out.println(cloneConcretePrototype.toString());

显示结果

执行了ConcretePrototype2构造函数
执行了ConcretePrototype2构造函数
ConcretePrototype2{name='原始数据', list=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 追加测试数据]}
ConcretePrototype2{name='拷贝数据', list=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 追加测试数据]}

【追加测试数据无论是原型还是拷贝后的对象都有这个数据】

问题原因:深拷贝-浅拷贝

Cloneable接口默认实现的是浅拷贝,对于基本类型会进行拷贝,但是对于引用类型(集合,数据,对象)等clone仅仅代表指向了同一个内存地址,所以修改一个两个都会变化。

解决方案:在引用类型的具体数据类型在进行一次clone,将浅拷贝处理为深拷贝

深拷贝代码实现

代码如下

  public ConcretePrototype2 clone() {
        //手动new对象进行赋值
//        ConcretePrototype2 concretePrototype2 = new ConcretePrototype2();
//        concretePrototype2.name = this.name;
//        concretePrototype2.list = this.list;
//        return concretePrototype2;
        
        //将具体的集合修改为深拷贝
        ConcretePrototype2 concretePrototype2 = new ConcretePrototype2();
        concretePrototype2.name = this.name;
        concretePrototype2.list = (ArrayList<String>) this.list.clone();

        return concretePrototype2;

    }
    

显示结果

执行了ConcretePrototype2构造函数
执行了ConcretePrototype2构造函数
ConcretePrototype2{name='原始数据', list=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}
ConcretePrototype2{name='拷贝数据', list=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 追加测试数据]}

应证我们的想法,对于集合,数组,对象等,如果要新增数据,需要对其重写更改具体的数据类型。

总结

原型模式可以避免构造复杂的对象时的资源消耗问题,提升创建对象的效率。
可以保护原始对象的数据安全性
clone是二进制流,对于复杂的构造对象,性能提升明显,但是对于简单的构造没必要使用clone

github代码地址

上一篇 下一篇

猜你喜欢

热点阅读