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

来源:互联网 发布:vb.net 高级编程 pdf 编辑:程序博客网 时间:2024/06/18 10:17

原型模式


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

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

new适用于简单的构造

clone适用于复杂的构造

应用场景

  • 资源消耗大的对象
  • 节省资源,比如在for循环内创建相同的对象
  • 一个对象要让其他人使用,并且使用过程中要改变这个对象的某些属性,可考虑将原有对象拷贝,并且修改需要改变的属性,在进行使用
  • 对象结构复杂的情况使用拷贝

浅拷贝代码实现

原型对象实现Cloneable接口默认是浅拷贝

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]}

原型对象不实现Cloneable接口默认是浅拷贝

其实就是把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代码地址

原创粉丝点击