因为类初始化需要消耗非常多的资源,包括数据、硬件资源等,通过原型拷贝则可以避免这些消耗,而且new一个对象会经过非常繁琐的数据准备或访问权限,假若一个对象需要供给其他对象访问,而且各个对象都需要修改其值时,可以拷贝多个对象供调用者访问,即保护性拷贝,以上就是用到原型模型的场景。总而言之,及时你需要用到一个对象,还需要修改该对象部分值,保留部分值,你就可以用它。下面就结合代码来说明一下
我们有一个对象,包含了一些文本和一些对象
原型模型,主要是实现Cloneable接口和覆写Object的clone方法
我们还是写一辆车,有品牌,重量,供应商,和拥有者的信息
/**
* @author: hx
* @Time: 2019/5/6
* @Description: Car
*/
public class Car implements Cloneable {
private String brand;
private int weight;
private ArrayList 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 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}}
----------------------
可以看到,我们只修改了第二辆车的信息,但是第一辆车的也一起改了,只是第一辆车的原本基本类型的值没有修改,所以可以得出结论,浅拷贝,在拷贝引用的时候,并没有拷贝对象,只是拷贝了对象的引用,所以我们需要对非基本类型也进行拷贝,即深拷贝。
在运用原型模式时建议还是用深拷贝,下面我们把上面的浅拷贝改成深拷贝
要注意的是,拷贝的时候是不走构造函数的
/**
* @author: hx
* @Time: 2019/5/6
* @Description: Car
*/
public class Car implements Cloneable {
private String brand;
private int weight;
private ArrayList 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 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) 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) 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效率会高一点。