原型模式定义 用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。 原型模式示例
public class Person implements Cloneable { private String name; private int age; private double height; private double weight; public Person(){} 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; } public double getHeight() { return height; } public void setHeight(double height) { this.height = height; } public double getWeight() { return weight; } public void setWeight(double weight) { this.weight = weight; } @Override public String toString() { return "Person[name:"+name+", age:"+age+", height:"+height+", weight:" + weight+"]"; } @Override protected Object clone() throws CloneNotSupportedException { Person person = null; try { person = (Person) super.clone(); person.name = this.name; person.age = this.age; person.height = this.height; person.weight = this.weight; } catch (CloneNotSupportedException e) { e.printStackTrace(); } return person; } }这是原型类的实现,需要Person类的副本的时候调用clone方法,会生成一个副本,可以在副本里面修改而不影响原始的实例对象。这就是是浅拷贝,所谓浅拷贝说白了就是把原对象所有的值和引用直接赋给新对象。不会运行构造方法,如果构造方法里面有处理,拷贝的时候需要在clone方法里面做特效处理。
public static void main(String[] args) throws CloneNotSupportedException { Person person = new Person(); person.setName("李四"); person.setAge(22); person.setHeight(1.56); person.setWeight(66); System.out.println(person); Person person2 = (Person) person.clone();//创建副本 System.out.println(person2); person2.setName("张三"); System.out.println(person2); person.setName("wangwu"); System.out.println(person); System.out.println(person2); }测试结果:
Person[name:李四, age:22, height:1.56, weight:66.0] Person[name:李四, age:22, height:1.56, weight:66.0] Person[name:张三, age:22, height:1.56, weight:66.0] Person[name:wangwu, age:22, height:1.56, weight:66.0] Person[name:张三, age:22, height:1.56, weight:66.0] 根据结果可以看出原型类和副本类的值互相不影响(不是引用类型,如果是引用类型,由于是浅拷贝,传递给副本的是引用类型的地址,两个互相影响,这里Person类里面没有引用类型,结果没有演示出来)。
有浅拷贝就有深拷贝,深拷贝则不仅把原对象的值赋给新对象,而且会把原对象的引用对象也重新创建一遍再赋给新对象(深拷贝,是把引用类型重新创建出来,所以副本的引用类型是和原型类里面的引用类型不是一个,互相不影响)。
示例:
public class Person { private String name; ....//省略了一些字段 private List<String> list; //省略get/set方法 public Object clone(){ ....//省略 if(list != null){ //深拷贝,重新创建引用对象 list = new ArrayList<String>(); } } }Android中原型模式的使用 下面通过Intent来分析源码中的原型模型:
Uri uri = Uri.parse("smsto:0800000124"); Intent shareIntent = new Intent(Intent.ACTION_SEND,uri); shareIntent.putExtra("sms_body","The SMS text"); //克隆副本 Intent intent = (Intent) shareIntent.clone(); startActivity(intent);上面的代码是创建一个发送短信的shareIntent,然后克隆给新的intent,通过intent跳转启动短信发送信息。 下面来看看Intent的源码怎么实现:
@Override public Object clone() { return new Intent(this); } /** * Copy constructor. */ public Intent(Intent o) { this.mAction = o.mAction; this.mData = o.mData; this.mType = o.mType; this.mPackage = o.mPackage; this.mComponent = o.mComponent; this.mFlags = o.mFlags; this.mContentUserHint = o.mContentUserHint; //深拷贝 if (o.mCategories != null) { this.mCategories = new ArraySet<String>(o.mCategories); } if (o.mExtras != null) { this.mExtras = new Bundle(o.mExtras); } if (o.mSourceBounds != null) { this.mSourceBounds = new Rect(o.mSourceBounds); } if (o.mSelector != null) { this.mSelector = new Intent(o.mSelector); } if (o.mClipData != null) { this.mClipData = new ClipData(o.mClipData); } }可以看到clone方法实际上没有调用super.clone()方法来实现,而是调用了new Intent(this).其实实现克隆clone()方法里面不一定非要super.clone()来创建对象,可以使用new创建。考虑使用clone还是new是需要根据构造对象的成本来决策。具体使用那一个根据效率是实现。
