美文网首页安卓开发Android进阶之路Android开发经验谈
移动架构师-设计模式篇 《原型模式》

移动架构师-设计模式篇 《原型模式》

作者: DevCW | 来源:发表于2018-03-07 10:45 被阅读48次

    原型模式,对于开发者而言,或陌生,或熟悉,但是都应该很熟悉Cloneable接口。通过Cloneable接口,我们可以很容易的复制一个对象副本来单独使用,当然,这取决于Class是否实现了该接口以及如何实现。

    原型模式是创建型的设计模式之一。官方而言,原型模式的作用是用指定原型对象来创建一个新的对象;从本身的功能与意义来理解的话,我们可以举个日常的例子。

    我们应该都写过周报或日报,但是我们在写周报或日报的时候,除非第一次,否则大多数人的做法都是复制上一次周报的文件,修改文件名称,并修改部分周报内容,然后提交。为什么呢? 因为一我们已经有了一个类似的文件, 二则新的文件或许与旧的文件内容不同,但很多内容却是相同的。复用上一次的,省时省力,何乐而不为呢?

    其实原型模式也是这样的。比如有一个产品A, A有100个字段;现在我们想要创建一个产品B,发现B很多特点和A都一样,可能部分属性是不同的;此时你会怎么做呢 ? 手动创建一个新的对象,还是从A的副本修改少部分属性呢 ? 答案显而易见。直接描述不够形象, 那么来一段简单的代码。

    // 这是一个学生类,很简单!
    public class Student implements Cloneable {
            public String name;
            public int age;
            public int sex;
    
            public Student(Student stu) {
                 this.name = stu.name;
                 this.age = stu.age;
                 this.sex = stu.sex;
            }
    
            @override
            public Object clone() {
                return new Student(this);
            }
    }
    
    pubic class Main {
      
          public static void main(String[] args) {
                      // 有一个学生,小明
                      Student stu_xiaoming = new Student();
                      stu_xiaoming.name = "xiaoming";
                      stu_xiaoming.age = 18;
                      stu_xiaoming.sex = 1;  
                      
                      // 小明有一个发小 小毛,同班同读,也是18岁, 男孩
                      // 如果是你,你怎么生成这个发小的对象呢 ?
                      // 这就是原型模式的作用
    
                      Student stu_faxiao = stu_xiaoming.clone();
                      stu_faxiao.name = "xiaomao"; 
          }
    }
    

    通过上面的描述与例子,我想已经都猜到了原型模式的作用了。可能有人会说, 就3个属性罢了,复制一下也是很快的; 但是在开发中, 可能一个产品会有几十个几百个属性,都要复制吗 ?而且复制会产生大量的类似代码,无论对结构,以及开发效率都是不利的。

    它主要面对的问题是:“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是他们却拥有比较稳定一致的接口。
    

    深拷贝与浅拷贝
    既然聊到复制, 我们来聊一下深拷贝与浅拷贝的问题。其实很好理解:
    1.基本变量如int,boolean,double等类型的变量采用=赋的是值,如

    int a = 10; 
    int b = a;
    int b = 5;
    // 此时a = 10, b = 5.  b的赋值不会影响a
    

    2.引用变量如List,String,数组等引用型的变量采用=赋得是址,即原引用和被赋值引用指向同一个地址,如

    int[] a = new int[]{1,2,3,4};
    int[] b = a;
    b[3] = 5;
    // 此时 a与b都是[1,2,3,5]。 b赋值给a,则a与b指向同一块内存空间,a与b对内存空间的修改,都同时生效 
    

    3.Class的属性既包含基本类型,也包含引用类型;Class中所有的变量以及嵌套变量都是深拷贝,那么Class才是深拷贝

    public class A implements Colneable {
        public int a; // 基本类型由于理论1,赋值后都是独立的
        public B b; // 引用对象如果
    
        @override 
        public Object clone() {
            A c = new A();
            c.a = this.a; // 基本类型不影响
            c.b = this.b; // 这里b是浅复制,此时两个引用指向同一内存, 相互影响
            // 以下是深复制,属性赋值后, 两者相互独立
            B d = new B();
            d.v = this.b.v;
            c.b = d;
        }
    }
    
    public class B {
            public int v;
    }
    

    最后的最后,结合Android的源码,来看一下原型模式的经典实现。今天的嘉宾是Intent, 大家可以借鉴~

    // 片段1 实现Cloneable接口
    public class Intent implements Parcelable, Cloneable {
    ...
    // 片段2 接下来看一下clone的实现
       @Override
        public Object clone() {
            return new Intent(this);
        }
    // 片段3 大家一定会好奇,构造方法才是关键,那构造方法里是什么呢 ?
    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;
            this.mLaunchToken = o.mLaunchToken;
            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);
            }
        }
    // 以上三步实现经典原型模式,同单例模式的讲解,借助官方的源码来完成我们自己的设计模式,才完美!
    

    从本篇可以看出, 原型模式是很简单的,也好理解。原型模式主要解决了复杂对象的创建问题,它有什么优点和缺点呢 ?如下

    1.隐藏了创建的细节,我们只知道clone生成一个副本,但是怎么生成,who knows ?
    2.比直接创建一个对象更有效率,特别是复杂对象,因为它操作内存中的二进制流
    3.省时省力省代码,复制很low,还会造成多余的代码,多次使用也很麻烦;总之复用比复制好太多


    原型模式很简单, 本篇文章亦是,如果你觉得有收获,不妨为我打Call !!!

    相关文章

      网友评论

        本文标题:移动架构师-设计模式篇 《原型模式》

        本文链接:https://www.haomeiwen.com/subject/utadfftx.html