Android开发之路手机移动程序开发Android知识

浅谈Android移动架构(三)创建模式之原型模式

2017-01-03  本文已影响154人  轻轻笑声
原型模式:

#######定义:
用原型的实例指定创建对象的种类,并通过拷贝这些原型创建新的对象.(通俗的意思:复制一个一模一样的对象出来.)
#######用途:
原型模式主用来创建的复杂的对象和构建耗时的实例。通过克隆已有的对象来创建的新的对象,从而节省时间和内存。通过克隆一个已经存在的实例可以使我们的程序运行的更高效。
#######直接上例子吧:
首先定义一个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 一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好滴体现其优点.
缺点:这既是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的,在实际开发中应该注意这个潜在问题,需要大家在实际应用是考虑.

上一篇下一篇

猜你喜欢

热点阅读