浅谈Android移动架构(三)创建模式之原型模式
原型模式:
#######定义:
用原型的实例指定创建对象的种类,并通过拷贝这些原型创建新的对象.(通俗的意思:复制一个一模一样的对象出来.)
#######用途:
原型模式主用来创建的复杂的对象和构建耗时的实例。通过克隆已有的对象来创建的新的对象,从而节省时间和内存。通过克隆一个已经存在的实例可以使我们的程序运行的更高效。
#######直接上例子吧:
首先定义一个Student(学生)类:
public class Student{
private String name;
private int age;
public Student(){
}
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 "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
要实现原型模式,只需要按照下面的几个步骤去实现即可。
1.实现Cloneable接口
2.重写Object的clone方法
3.实现clone方法中的拷贝逻辑
实现后代码:
public class Student implements Cloneable{
private String name;
private int age;
public Student(){
}
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 "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public Object clone() {
Student student=null;
try {
student=(Student)super.clone();
student.name=this.name;
student.age=this.age;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return student;
}
}
调用代码:
public class Client {
public static void main(String [] args){
Student s=new Student();
s.setName("张三");
s.setAge(18);
System.out.println(s);
Student s1= (Student) s.clone();
System.out.println(s1);
s1.setName("李四");
System.out.println(s);
System.out.println(s1);
}
}
输出结果:
Student{name=’张三’, age=18}
Student{name=’张三’, age=18}
Student{name=’张三’, age=18}
Student{name=’李四’, age=18}
以上就是java中一个简单的原型模式.
#######深拷贝与浅拷贝
假设Student类里还有一个属性叫兴趣爱好,是一个List集合,就像这样子:
private ArrayList<String> hobbies=new ArrayList<String>();
public ArrayList<String> getHobbies() {
return hobbies;
}
public void setHobbies(ArrayList<String> hobbies) {
this.hobbies = hobbies;
}
在进行拷贝的时候要格外注意,如果你直接按之前的代码那样拷贝:
@Override
public Object clone(){
Student student=null;
try {
student=(Student)super.clone();
student.name=this.name;
student.age=this.age;
person.hobbies=this.hobbies;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return student;
}
调用代码:
public class Client {
public static void main(String [] args){
Student s=new Student();
s.setName("张三");
s.setAge(18);
ArrayList <String> hobbies=new ArrayList<String>();
hobbies.add("篮球");
hobbies.add("编程");
hobbies.add("长跑");
s.setHobbies(hobbies);
System.out.println(s);
Student s1= (Person) s.clone();
System.out.println(s1);
s1.setName("李四");
s1.getHobbies().add("游泳");
System.out.println(s);
System.out.println(s1);
}
}
打印结果:
Student{name=’张三’, age=18, hobbies=[篮球, 编程, 长跑]}
Student{name=’张三’, age=18, hobbies=[篮球, 编程, 长跑]}
Student{name=’张三’, age=18, hobbies=[篮球, 编程, 长跑, 游泳]}
Student{name=’李四’, age=18, hobbies=[篮球, 编程, 长跑, 游泳]}
你会发现原来的对象的hobby也发生了变换。
其实导致这个问题的本质原因是我们只进行了浅拷贝,也就是只拷贝了引用,最终两个对象指向的引用是同一个,一个发生变化另一个也会发生变换,显然解决方法就是使用深拷贝。
@Override
public Object clone(){
Student student=null;
try {
student=(Student)super.clone();
student.name=this.name;
student.age=this.age;
student.hobbies=(ArrayList<String>)this.hobbies.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return student;
}
注意student.hobbies=(ArrayList)this.hobbies.clone();,不再是直接引用而是进行了一份拷贝。再运行一下,就会发现原来的对象不会再发生变化了。
打印结果:
Student{name=’张三’, age=18, hobbies=[篮球, 编程, 长跑]}
Student{name=’张三’, age=18, hobbies=[篮球, 编程, 长跑]}
Student{name=’张三’, age=18, hobbies=[篮球, 编程, 长跑]}
Student{name=’李四’, age=18, hobbies=[篮球, 编程, 长跑, 游泳]}
#######Android中会更多的看到原型模式的另一种写法:
@Override
public Object clone(){
return new Student(this);
}
其实是在构造函数中完成拷贝逻辑:
public Student(Student student){
this.name=student.name;
this.weight=student.weight;
this.height=student.height;
this.age=student.age;
this.hobbies= new ArrayList<String>(hobbies);
}
那么原型模式,在我们的Android中有什么经典应用呢?看看Intenet源码。
*
* <p>These are the possible flags that can be used in the Intent via
* {@link #setFlags} and {@link #addFlags}. See {@link #setFlags} for a list
* of all possible flags.
*/
public class Intent implements Parcelable, Cloneable {
@Override
public Object clone() {
return new Intent(this);
}
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);
}
}
}
#######最后来一个实际应用的例子(自己实现原型接口):
shili.png
假设客户给工厂一个订单(订单即是合同),合同上要求你工厂生产3000个商品,然而工厂每个班组只能生产1000个,生产完后靶合同数量做更改的交给不同的班组,想下原合同厂里肯定是要保留的啊,那么给车间班组的只能是做过修改的复制品.
代码如下:
1.首先提供一个接口:
public interface Prototype {
Prototype cloneOrder();
}
2.再定义一个接口继承interface Prototype:
public interface IOrder extends Prototype {
int getOderNumber();
void setOderNumber(int number);
}
3.接口 Iorder的实现类
public class PersonOrder implements IOrder{
private int oderNumber;
private String name;
@Override
public int getOderNumber() {
return oderNumber;
}
@Override
public void setOderNumber(int number) {
oderNumber=number;
}
public String getOrderName() {
return name;
}
public void setOrderName(String name) {
this.name=name;
}
@Override
public Prototype cloneOrder() {
PersonOrder personOrder=new PersonOrder();
personOrder.setOderNumber(oderNumber);
personOrder.setOrderName(name);
return personOrder;
}
}
4.工厂类:
public class OrderDealFactory {
public void dealOrder(IOrder order)
{
System.out.println("原订单地址 : "+order.hashCode());
int number=order.getOderNumber();
while (number>0) {
IOrder iOrder=(IOrder) order.cloneOrder();
iOrder.setOderNumber(number>1000?1000:number);
number-=1000;
System.out.println("订单---- number "+iOrder.getOderNumber()+
"地址 : "+iOrder.hashCode());
}
}
}
5.执行:
public class Client {
public static void main(String[] args) {
OrderDealFactory orderDealFactory=new OrderDealFactory();
PersonOrder order=new PersonOrder();
order.setOderNumber(3500);
order.setOrderName("个人订单");
orderDealFactory.dealOrder(order);
}
}
#######总结:
优点:原型模式是在内存中二进制流的拷贝,要比直接 new 一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好滴体现其优点.
缺点:这既是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的,在实际开发中应该注意这个潜在问题,需要大家在实际应用是考虑.