美文网首页Material DesignAndroidAndroid进阶
经典Builder/变种Builder模式及自动化生成代码插件

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

作者: 青蛙要fly | 来源:发表于2016-12-01 23:26 被阅读2439次

    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);
            }
        }
    }
    

    相关文章

      网友评论

      • mundane:" new Director(new SquareCookiesBuilder()).createCookies().getCookies()"

        Director类的createCookies()方式是void的返回类型怎么还能继续.getCookies()?
      • 戴定康:还行
      • 5fb241b9ff8b:兄弟你这个获得方形饼干和圆形饼干不能链式调用把,你都没有返回当前类怎么调用的?

      本文标题:经典Builder/变种Builder模式及自动化生成代码插件

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