经典Builder/变种Builder模式及自动化生成代码插件

Builder模式是一种广泛使用的设计模式。

将一个复杂对象的构建与它的表示分立,这样在调用相同构建的过程中可以创建不同的表示

Builder模式分二种,一种是经典的Builder模式,第二种是变种Builder模式,而现在Android开发普遍使用的是第二种的变种Builder模式,下面我们一一来介绍。

---------------------------------我是分割线,不分不舒服------------------------

经典的Builder模式

经典Buider模式分为四块:

  • Product:被构造的复杂对象。
  • Builder:抽象接口。
  • BuilderImpl:抽象接口的具体实现。
  • Director:接口的构造者和使用者。
这张图是我其它地方看到偷的。嘎嘎

举个最简单的例子。
现在有个厂要生产不同的饼干,有方形的,圆形的等。

我们先建立饼干的类

public class Cookies {
    private String shape;
    
    public String getShape(){
        return shape;
    }
    
    public void setShape(String shape){
        this.shape = shape;
    }
}

然后我们创建Builder接口

public interface Builder{
    public void setShape();
    public Cookies getCookies();
}

然后实现Builder接口,比如创建一个会建立方形饼干的SquareCookiesBuilder和一个会建立圆形饼干的RoundCookiesBuilder

public class SquareCookiesBuilder implements Builder{
    private Cookies cookies;
    @Override
    public SquareCookiesBuilder(){
        this.cookies = new Cookies();
    }
    
    @Override
    public void setShape(){
        this.cookies.setShape("方形");
    }
    
    @Override
    public Cookies getCookies(){
        return this.cookies;
    }
}



public class RoundCookiesBuilder implements Builder{
    private Cookies cookies;
    @Override
    public RoundCookiesBuilder(){
        this.cookies = new Cookies();
    }
    
    @Override
    public void setShape(){
        this.cookies.setShape("圆形");
    }
    
    @Override
    public Cookies getCookies(){
        return this.cookies;
    }
}

最后创建Director类

public class Director {
  
    private Builder builder;
    
    public Director(Builder builder){
            this.builder = builder;
    }
    
    public void createCookies(){
        this.builder.setShape()
    }
    
    public Cookies getCookies(){
        return this.builder.getCookies();
    }
}

这样就是
比如获取方形的饼干

new Director(new SquareCookiesBuilder()).createCookies().getCookies()

比如获取圆形的饼干。

new Director(new RoundCookiesBuilder()).createCookies().getCookies()

二者的区别就是对Director传入不同形状饼干的Builder的实现类。
而Director的对象调用的方法都是createCookies()和getCookies()

所以经典的Builder模式重点在于抽象出对象创建的步骤,并通过调用不同的具体实现类从而得到不同的结果,而变种的Builder模式的目的在于减少对象创建过程中引入的多个重载构造函数,可选参数以及setters过度使用导致的不必要的复杂性

--------------------------我是变种分割线O(∩_∩)O~----------------------------

变种Builder模式

我们一步步来。比如还是Cookies举例。就单纯的还是形状。

public class Cookies {
    private final String shape;
}

(一般来说,我们尽量将属性值定义为不可变的。总不能饼干都已经做成方的了。再把它改成圆形吧)

那这时候怎么对这个shape赋值呢。你可能会想到

  • 构造函数

因为参数是final类型了。所以必须在构造函数中进行初始化,否则不能编译通过

public class Cookies {
   private final String shape;
   
   pubic class Cookies(String shape){
       this.shape = shape;
   }
}

这样看是没问题。但是如果我们不是饼干,是一个人:Person类。它有name,gender,age三个属性。但是用户并不是要每个属性都要输入的。这时候就要建立多个构造函数。

public class Person {
    private final String name;
    private final String gender;
    private final String age;
    
    pubic class Person(String name){
        this(name,"男","20");
    }
    
    pubic class Person(String name,String gender){
        this(name,gender,"20")
    }
    
    pubic class Person(String name,String gender,String age){
        this.name = name;
        this.gender = gender;
        this.age = age;
    }
    
    
}

这种构造函数虽然简单,但是当属性多了的时候。代码就会变得不易维护,而且构造函数里面的参数的顺序也很容易弄错。当参数有五个。你还记得第几个参数要填年龄?记得第几个参数要填姓名?

  • getters 和 setters 函数
public class Cookies {
    private String shape;
    
    public void setShape(String shape){
        this.shape = shape;
    }
    
    public String getShape(){
        return this.shape;
    }
}

优点:你可以建立对象,然后对你想要修改的属性进行修改,比如有二个属性,你可以只要调用你想修改的属性的set方法就可以进行修改。
缺点:
1.因为是set方法,所以shape的参数不在是final修饰了,因为你本身可以多次调用set方法。这样Cookies类就变成可变类了。失去了不可变类的好处了。
2.比如刚那个Person类,有三个属性。当你要给它的对象赋值这三个属性的时候,就要

Person person = new Person();
person.setName("青蛙ing");
person.setAge("20");
person.setGender("男");

失去一种连贯的感觉,而且这还只有三个属性。要是10个。你这样一行行的set方法写十遍??

----------------------我是主角分割线(我是主角!!)--------------------
还是以上面的Person类为例子。


public class Person {
    
    private final String name;
    private final String gender;
    private final String age;

    private Person(Builder builder) {
        name = builder.name;
        gender = builder.gender;
        age = builder.age;
    }

    public String getName() {
        return name;
    }

    public String getGender() {
        return gender;
    }

    public String getAge() {
        return age;
    }

    public static final class Builder {
        private String name;
        private String gender;
        private String age;

        public Builder() {
        }

        public Builder name(String val) {
            name = val;
            return this;
        }

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

        public Builder age(String val) {
            age = val;
            return this;
        }

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


从上述代码可以看出:
1.Person类的构造函数是私有的。这样就不能直接实例化这个类
2.Person类是不可变的。里面的属性都是final的。只能在构造函数中初始化。然后提供了属性的get函数,可以去获取值。
3.连贯性,这个Person的创建是:
new Person.Builder().name("青蛙ing").gender("男").age("20").build();
就问你这么写爽不爽。!!


------------------------------我是插件介绍线------------------------------------
这一段我就不自己截图了。
就引用别人的插件介绍了。
感谢CSDN的拭心
从他的文章里面拿了插件介绍的图片和内容
http://blog.csdn.net/u011240877/article/details/53248917

变种Builder模式自动化生成

1.下载插件 InnerBuilder:

2.重启 Andriod Studio;

3.写好要构建的类的变量:

比如:

public class PersonTest {
    private final String mName;
    private int mAge;
    private String mLocation;

}

4.按 Control + Insert (Mac :command + N):


5.在弹出的 Generate 对话框中选择 Builder:


6.选中要使用 Builder 构建的对象,然后勾选使用的配置,点击OK

public class PersonTest {
    private final String mName;
    private int mAge;
    private String mLocation;

    private PersonTest(Builder builder) {
        mName = builder.mName;
        mAge = builder.mAge;
        mLocation = builder.mLocation;
    }

    public static final class Builder {
        private String mName;
        private int mAge;
        private String mLocation;

        public Builder() {
        }

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

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

        public Builder mLocation(String mLocation) {
            this.mLocation = mLocation;
            return this;
        }

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

推荐阅读更多精彩内容