小点知识——构造模式(Builder模式)

构造模式(Builder模式)

定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示、

概念:比较抽象的,让大家很难理解的,如果简单从这个一个概念就搞懂了这个模式的话,那就不用费力的去查资料整理后边的东西了。

作用:Builder模式的目的在于减少对象创建过程中引用的多个重载构造方法、可选参数和setters过度使用导致的不必要的复杂性。

通过一个例子来引出Build模式。假设有一个Student类,该类的一些属性可以为null,可以通过这个类来构架一大批学生


public class Student {

    private String mParentName;//父母的名字
    private String mParentTel;//父母的电话
    private String mHomeAddress;//家庭地址
    private String mName;//名字
    private int mAge;//年龄
    private String mGender;//性别

    public String getmParentName() {
        return mParentName;
    }

    public void setmParentName(String mParentName) {
        this.mParentName = mParentName;
    }

    public String getmParentTel() {
        return mParentTel;
    }

    public void setmParentTel(String mParentTel) {
        this.mParentTel = mParentTel;
    }

    public String getmHomeAddress() {
        return mHomeAddress;
    }

    public void setmHomeAddress(String mHomeAddress) {
        this.mHomeAddress = mHomeAddress;
    }

    public String getmName() {
        return mName;
    }

    public void setmName(String mName) {
        this.mName = mName;
    }

    public int getmAge() {
        return mAge;
    }

    public void setmAge(int mAge) {
        this.mAge = mAge;
    }

    public String getmGender() {
        return mGender;
    }

    public void setmGender(String mGender) {
        this.mGender = mGender;
    }
}

然后为了方便,我们可能会写这么一个构造函数来传属性


public Student(String mParentName, String mParentTel, String mHomeAddress, String mName, int mAge, String mGender) {
        this.mParentName = mParentName;
        this.mParentTel = mParentTel;
        this.mHomeAddress = mHomeAddress;
        this.mName = mName;
        this.mAge = mAge;
        this.mGender = mGender;
    }

或者为了更方便还会写一个空的构造函数

public Student (){}

有时候还会比较懒,只传入某些参数,又会来写这些构造函数

public Student(String mParentName, String mParentTel, String mName) {
        this.mParentName = mParentName;
        this.mParentTel = mParentTel;
        this.mName = mName;
    }

public Student(String mName) {
        this.mName = mName;
    }

于是就可以来创建各种需要的类的对象。

Student s1 = new Student();
Student s2 = new Student("name");
Student s3 = new Student("mParentName","mParentTel","mName");
Student s4 = new Student("mParentName","mParentTel","mHomeAddress","mName","mAge","mGender");

其实这种写法的坏处在你写的过程中就该想到了,既然就是一个创建对象的过程,怎么这么繁琐,并且构造函数参数过多或不同,其他人创建对象的时候怎么知道各个参数代表什么意思呢,这个时候我们为了代码的可读性,就可以用一下Builder模式了。给Student类添加一个静态Builder类,然后修改Student的构造函数。


public class Student {
    private String mParentName;//父母的名字  必写
    private String mParentTel;//父母的电话   必写
    private String mHomeAddress;//家庭地址   必写
    private String mName;//名字
    private int mAge;//年龄
    private String mGender;//性别

    private Student (Builder builder){
        mParentName = builder.mParentName;
        mParentTel = builder.mParentTel;
        mName = builder.mName;
        mAge = builder.mAge;
        mHomeAddress = builder.mHomeAddress;
        mGender = builder.mGender;
    }

    public String getmParentName() {
        return mParentName;
    }

    public void setmParentName(String mParentName) {
        this.mParentName = mParentName;
    }

    public String getmParentTel() {
        return mParentTel;
    }

    public void setmParentTel(String mParentTel) {
        this.mParentTel = mParentTel;
    }

    public String getmName() {
        return mName;
    }

    public void setmName(String mName) {
        this.mName = mName;
    }

    public int getmAge() {
        return mAge;
    }

    public void setmAge(int mAge) {
        this.mAge = mAge;
    }

    public String getmHomeAddress() {
        return mHomeAddress;
    }

    public void setmHomeAddress(String mHomeAddress) {
        this.mHomeAddress = mHomeAddress;
    }

    public String getmGender() {
        return mGender;
    }

    public void setmGender(String mGender) {
        this.mGender = mGender;
    }


    public static final class Builder{
        private String mParentName;//父母的名字
        private String mParentTel;//父母的电话
        private String mName;//名字
        private int mAge;//年龄
        private String mHomeAddress;//家庭地址
        private String mGender;//性别

        public Builder (String parentName ,String parentTel){//说明这两个参数是必填写的,当然你也可以设置成不必填写(看需求吧)
            mParentName = parentName;
            mParentTel = parentTel;

        }

        public Builder setName(String studentName){
            mName = studentName;
            return this;
        }

        public Builder setAge(int age){
            mAge = age;
            return this;
        }

        public Builder setHomeAddress(String homeAddress){
            mHomeAddress = homeAddress;
            return this;
        }

        public Builder setGender(String gender){
            mGender = gender;
            return this;
        }

        public Student build(){
            return new Student(this);
        }
    }
}

从上面代码我们可以看到我们在Builder类中定义了一份跟Student类一样的属性,通过一系列的成员函数进行赋值,但是返回的都是this,最后提供了一个build函数来创建Student对象,对应的在Student的构造函数中,传入了Builder对象,然后依次对自己的成员变量进行赋值。此外,Builder类也有一个要传参的构造方法,其参数是必须的传入(这几个参数也就是说Student类里必须赋值的),当然也可以构造一个空的构造方法。Builder的成员函数返回的都是this的另一个作用就是让他支持链式调用,使代码可读性大大增强。

那么我们就可以这样创建Student对象。


public class TestJava {
    public static void main(String agr[]){
        Student student = new Student.Builder("卢家长","13811112222")
        .setName("卢一")
        .setAge(10)
        .setHomeAddress("夏郢")
        .setGender("男")
        .build();

        System.out.println(student.getmParentName());
        System.out.println(student.getmParentTel());
        System.out.println(student.getmName());
        System.out.println(student.getmAge());
        System.out.println(student.getmHomeAddress());

        Student.Builder builder = new Student.Builder("lu家长","13422221111");
        Student stu = builder.setName("卢三")
                .setHomeAddress("福田")
                .build();
        System.out.println("===========================");
        System.out.println(stu.getmParentName());
        System.out.println(stu.getmParentTel());
        System.out.println(stu.getmName());
        System.out.println(stu.getmAge());
        System.out.println(stu.getmHomeAddress());

    }

}

用Builder模式是不是简单又清楚,主要是在Student类不用大量构造不同的构造方法,根据需求赋值就可以了,并且容易维护,扩展性强。

Android中大量地方运用到了Builder模式,比如常见的对话框创建。


AlertDialog.Builder builder=new AlertDialog.Builder(this);    
AlertDialog dialog=builder.setTitle("我就是用BUILDER模式的对话框")    
        .setIcon(android.R.drawable.ic_dialog)    
        .setView(R.layout.custom_view)    
        .setPositiveButton(R.string.positive, new DialogInterface.OnClickListener() {    
            @Override    
            public void onClick(DialogInterface dialog, int which) {    
    
            }    
        })    
        .setNegativeButton(R.string.negative, new DialogInterface.OnClickListener() {    
            @Override    
            public void onClick(DialogInterface dialog, int which) {    
    
            }    
        })    
        .create();    
dialog.show();   

ImageLoader使用Builder设计模式

    private void initImageLoader() {
        ImageLoaderConfiguration.Builder config = new
        ImageLoaderConfiguration.Builder(getContext());
        config.threadPriority(Thread.NORM_PRIORITY - 2);
        config.denyCacheImageMultipleSizesInMemory();
        config.memoryCacheSize(5 * 1024 * 1024);// 5M
        config.tasksProcessingOrder(QueueProcessingType.LIFO);
        ImageLoader.getInstance().init(config.build());
    }

Gson中的GsonBuilder也运用了Builder设计模式


GsonBuilder builder=new GsonBuilder();    
Gson gson=builder.setPrettyPrinting()    
        .disableHtmlEscaping()    
        .generateNonExecutableJson()    
        .serializeNulls()    
        .create(); 

平时用得最多的网络框架OKHttp也运用了Builder设计模式


Request.Builder builder=new Request.Builder();    
Request request=builder.addHeader("","")    
    .url("")    
    .post(body)    
    .build();    


当你们在开发中注意过源代码亦或大量框架代码时,就会惊讶地发现里面也运用了Builder设计模式。
Android Studio自动生成变种Builder模式。如果你的Android Studio中没有安装InnerBuilder插件,则先去安装。
安装好后重启Android Studio,只需要把属性名确定下来,alt键+insert键,选择builder按钮即可(快捷键Alt+Shift+B)。

总结

  1. 在类中定义一个静态内部类Builder,内部成员变量跟外部一样。

  2. 如果某些成员变量是必传输值时,可以在Builder的构造方法中协带。反之可以不用构造方法。

  3. Builder通过一系列方法给成员变量赋值,并返回当前对象(this)。

  4. Builder类内部提供一个build方法方法或者create方法用于创建对应的外部类,该方法内部调用了外部类的一个私有化构造方法,该构造方法的参数就是内部类Builder。

  5. 外部类提供一个私有化的构造方法供内部类调用,在该构造函数中完成成员变量的赋值。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 227,283评论 6 530
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 97,947评论 3 413
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 175,094评论 0 373
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 62,485评论 1 308
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 71,268评论 6 405
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 54,817评论 1 321
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 42,906评论 3 440
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 42,039评论 0 285
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 48,551评论 1 331
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 40,502评论 3 354
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 42,662评论 1 366
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 38,188评论 5 356
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 43,907评论 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 34,304评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 35,563评论 1 281
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 51,255评论 3 389
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 47,637评论 2 370

推荐阅读更多精彩内容