android设计模式二十三式(四)——原型模式(Prototype)

原型模式

因为类初始化需要消耗非常多的资源,包括数据、硬件资源等,通过原型拷贝则可以避免这些消耗,而且new一个对象会经过非常繁琐的数据准备或访问权限,假若一个对象需要供给其他对象访问,而且各个对象都需要修改其值时,可以拷贝多个对象供调用者访问,即保护性拷贝,以上就是用到原型模型的场景。总而言之,及时你需要用到一个对象,还需要修改该对象部分值,保留部分值,你就可以用它。下面就结合代码来说明一下

我们有一个对象,包含了一些文本和一些对象

原型模型,主要是实现Cloneable接口和覆写Object的clone方法

1.浅拷贝

我们还是写一辆车,有品牌,重量,供应商,和拥有者的信息

/**
 * @author: hx
 * @Time: 2019/5/6
 * @Description: Car
 */
public class Car implements Cloneable {
    private String brand;
    private int weight;
    private ArrayList<String> supplier = new ArrayList<>();
    private Owner mOwner = new Owner();

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public List<String> getSupplier() {
        return supplier;
    }

    public void setSupplier(String... factoryName) {
        for (int i = 0; i < factoryName.length; i++) {
            supplier.add(factoryName[i]);
        }
    }

    public Owner getOwner() {
        return mOwner;
    }

    public void setOwner(String name, int age) {
        mOwner.setName(name);
        mOwner.setAge(age);
    }

    @Override
    public String toString() {
        return "Car{" +
                "brand='" + brand + '\'' +
                ", weight=" + weight +
                ", supplier=" + supplier +
                ", mOwner=" + mOwner +
                '}';
    }

    @Override
    public Car clone() throws CloneNotSupportedException {
        System.out.println("clone时不执行构造函数");
        Car car = (Car) super.clone();
        return car;
    }

    static class Owner {
        private String name;
        private int age;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        @Override
        public String toString() {
            return "Owner{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
}
public static void main(String[] args) throws CloneNotSupportedException {
    Car car1 = new Car();
    car1.setBrand("保时捷");
    car1.setWeight(1895);
    car1.setOwner("张三",33);
    car1.setSupplier("车轮","方向盘");
    System.out.println(car1.toString());
    System.out.println("----------------------");
    Car car2 = car1.clone();
    System.out.println(car2.toString());
    System.out.println("----------------------");
}

输出结果:

Car{brand='保时捷', weight=1895, supplier=[车轮, 方向盘], mOwner=Owner{name='张三', age=33}}
----------------------
clone时不执行构造函数
Car{brand='保时捷', weight=1895, supplier=[车轮, 方向盘], mOwner=Owner{name='张三', age=33}}
----------------------

看起来并没有什么问题,对吧,我们来定制一下第二辆车的信息

public static void main(String[] args) throws CloneNotSupportedException {
    Car car1 = new Car();
    car1.setBrand("保时捷");
    car1.setWeight(1895);
    car1.setOwner("张三",33);
    car1.setSupplier("车轮","方向盘");
    System.out.println("car1="+car1.toString());
    System.out.println("----------------------");
    Car car2 = car1.clone();
    car2.setWeight(2000);
    car2.setOwner("李四",50);
    car2.setSupplier("底盘");
    System.out.println("car1="+car1.toString());
    System.out.println("----------------------");
    System.out.println("car2="+car2.toString());
    System.out.println("----------------------");
}

输出结果:

car1=Car{brand='保时捷', weight=1895, supplier=[车轮, 方向盘], mOwner=Owner{name='张三', age=33}}
----------------------
clone时不执行构造函数
car1=Car{brand='保时捷', weight=1895, supplier=[车轮, 方向盘, 底盘], mOwner=Owner{name='李四', age=50}}
----------------------
car2=Car{brand='保时捷', weight=2000, supplier=[车轮, 方向盘, 底盘], mOwner=Owner{name='李四', age=50}}
----------------------

可以看到,我们只修改了第二辆车的信息,但是第一辆车的也一起改了,只是第一辆车的原本基本类型的值没有修改,所以可以得出结论,浅拷贝,在拷贝引用的时候,并没有拷贝对象,只是拷贝了对象的引用,所以我们需要对非基本类型也进行拷贝,即深拷贝。

2.深拷贝

在运用原型模式时建议还是用深拷贝,下面我们把上面的浅拷贝改成深拷贝

要注意的是,拷贝的时候是不走构造函数的

/**
 * @author: hx
 * @Time: 2019/5/6
 * @Description: Car
 */
public class Car implements Cloneable {
    private String brand;
    private int weight;
    private ArrayList<String> supplier = new ArrayList<>();
    private Owner mOwner = new Owner();

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public List<String> getSupplier() {
        return supplier;
    }

    public void setSupplier(String... factoryName) {
        for (int i = 0; i < factoryName.length; i++) {
            supplier.add(factoryName[i]);
        }
    }

    public Owner getOwner() {
        return mOwner;
    }

    public void setOwner(String name, int age) {
        mOwner.setName(name);
        mOwner.setAge(age);
    }

    @Override
    public String toString() {
        return "Car{" +
                "brand='" + brand + '\'' +
                ", weight=" + weight +
                ", supplier=" + supplier +
                ", mOwner=" + mOwner +
                '}';
    }

    @Override
    public Car clone() throws CloneNotSupportedException {
        System.out.println("clone时不执行构造函数");
        Car car = (Car) super.clone();
        car.supplier = (ArrayList<String>) this.supplier.clone();
        car.mOwner = (Owner) this.mOwner.clone();
        return car;
    }

    static class Owner implements Cloneable{
        private String name;
        private int age;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

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

        @Override
        protected Object clone() throws CloneNotSupportedException {
            Owner owner = (Owner) super.clone();
            return owner;
        }
    }

}

看一下运行结果

public static void main(String[] args) throws CloneNotSupportedException {
    Car car1 = new Car();
    car1.setBrand("保时捷");
    car1.setWeight(1895);
    car1.setOwner("张三",33);
    car1.setSupplier("车轮","方向盘");
    System.out.println("car1="+car1.toString());
    System.out.println("----------------------");
    Car car2 = car1.clone();
    car2.setWeight(2000);
    car2.setOwner("李四",50);
    car2.setSupplier("底盘");
    System.out.println("car1="+car1.toString());
    System.out.println("----------------------");
    System.out.println("car2="+car2.toString());
    System.out.println("----------------------");
}

输出结果:

car1=Car{brand='保时捷', weight=1895, supplier=[车轮, 方向盘], mOwner=Owner{name='张三', age=33}}
----------------------
clone时不执行构造函数
car1=Car{brand='保时捷', weight=1895, supplier=[车轮, 方向盘], mOwner=Owner{name='张三', age=33}}
----------------------
car2=Car{brand='保时捷', weight=2000, supplier=[车轮, 方向盘, 底盘], mOwner=Owner{name='李四', age=50}}
----------------------

 可以看到,深拷贝的之后,再修改拷贝对象就不会对原始对象的值有所影响。

为了防止遗漏,一般都是将所有的值都会进行一次赋值,即

    @Override
    public Car clone() throws CloneNotSupportedException {
        System.out.println("clone时不执行构造函数");
        Car car = (Car) super.clone();
        car.brand = this.brand;
        car.weight = this.weight;
        car.supplier = (ArrayList<String>) this.supplier.clone();
        car.mOwner = (Owner) this.mOwner.clone();
        return car;
    }



    @Override
    protected Object clone() throws CloneNotSupportedException {
        Owner owner = (Owner) super.clone();
        owner.name = this.name;
        owner.age = this.age;
        return owner;
    }

 在android中,其实还有的会将赋值行为放到构造函数中,然后在clone方法中直接new一个自己的对象。如Intent对象

/**
     * Copy constructor.
     */
    public Intent(Intent o) {
        this(o, COPY_MODE_ALL);
    }

    private Intent(Intent o, @CopyMode int copyMode) {
        this.mAction = o.mAction;
        this.mData = o.mData;
        this.mType = o.mType;
        this.mPackage = o.mPackage;
        this.mComponent = o.mComponent;

        if (o.mCategories != null) {
            this.mCategories = new ArraySet<>(o.mCategories);
        }

        if (copyMode != COPY_MODE_FILTER) {
            this.mFlags = o.mFlags;
            this.mContentUserHint = o.mContentUserHint;
            this.mLaunchToken = o.mLaunchToken;
            if (o.mSourceBounds != null) {
                this.mSourceBounds = new Rect(o.mSourceBounds);
            }
            if (o.mSelector != null) {
                this.mSelector = new Intent(o.mSelector);
            }

            if (copyMode != COPY_MODE_HISTORY) {
                if (o.mExtras != null) {
                    this.mExtras = new Bundle(o.mExtras);
                }
                if (o.mClipData != null) {
                    this.mClipData = new ClipData(o.mClipData);
                }
            } else {
                if (o.mExtras != null && !o.mExtras.maybeIsEmpty()) {
                    this.mExtras = Bundle.STRIPPED;
                }

                // Also set "stripped" clip data when we ever log mClipData in the (broadcast)
                // history.
            }
        }
    }

    @Override
    public Object clone() {
        return new Intent(this);
    }

 执行Intent的clone方法时,实际上是重新new了一个对象,具体是选择clone对象还是new一个对象,就看实际创建对象的成本和场景,如果构造很麻烦或者成本太高,还是选择clone效率会高一点。

优点

  • 可以解决复杂对象创建时消耗过多的问题,在某些场景下提升创建对象的效率。
  • 保护性拷贝,可以防止外部调用者对对象的修改,保证这个对象是只读的。

缺点

  • 拷贝对象时不会执行构造函数。
  • 有时需要考虑深拷贝和浅拷贝的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值