在此声明:以下内容由书籍 《Android高级进阶》学习而来。



Builder模式是一种设计模式,最初被介绍于《设计模式:可复用面向对象软件的基础》,目前在Java及Android中用处更是十分广泛,因此基本的了解与学习应当掌握。

一. Builder模式介绍

首先从它的定义开始介绍:

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

一般而言,Builder模式主要由四个部分组成:

  • Product :被构造的复杂对象,ConcreteBuilder 用来创建该对象的内部表示,并定义它的装配过程。
  • Builder :抽象接口,用来定义创建 Product 对象的各个组成部分的组件。
  • ConcreteBuilder : Builder接口的具体实现,可以定义多个,是实际构建Product 对象的地方,同时会提供一个返回 Product 的接口。
  • Director : Builder接口的构造者和使用者。


以代码的形式来进行说明,首先创建Product 类:

public class Product {    private String partOne;    private String partTwo;    public String getPartOne() {        return partOne;    }    public void setPartOne(String partOne) {        this.partOne = partOne;    }    public String getPartTwo() {        return partTwo;    }    public void setPartTwo(String partTwo) {        this.partTwo = partTwo;    }}

创建Builder接口:

public interface Builder {    public void buildPartOne();    public void buildPartTwo();    public void getProduct();}

创建两个ConcreteBuilder 类,即实现Builder接口:

public class ConcreteBuilderA implements Builder {    private Product product;    @Override    public void buildPartOne() {       }    @Override    public void buildPartTwo() {    }    @Override    public Product getProduct() {        return product;    }}
public class ConcreteBuilderB implements Builder {    private Product product;    @Override    public void buildPartOne() {       }    @Override    public void buildPartTwo() {    }    @Override    public Product getProduct() {        return product;    }}

最后创建Director

public class Director {    private Builder builder;    public Director(Builder builder){        this.builder = builder;    }    public  void buildProduct(){        this.builder.buildPartOne();        this.builder.buildPartTwo();    }    public Product getProduct(){        return this.builder.getProduct();    }}





二. Builder模式进化

以上代码只是最基本的展示了Builder模式,基于定义的介绍。这种基本模式重点在于:抽象出对象创建的步骤,并通过调用不同的具体实现从而得到不同的结果。 但是在实际运用中并非是以上形式,而是进化成另一种体现形式,目的在于 减少对象创建过程中引入的多个重载构造函数、可选参数以及setter过度使用导致不必要的复杂性。



下面还是以代码的形式来进行讲解,只是这次更加具体到一个熟悉的对象User,假以它有以下属性,且都是不可变(final)的。【应尽量将属性值定义为不可变】

public class User {    private final String mName;     //必选    private final String mGender;   //可选    private final int mAge;         //可选    private final String mPhone;    //可选}

这个 User类中 mName属性是必选的,其余的可选,接下来该如何构造这个实例呢?在此有两个前提:

  • 所有属性值以声明为 final,因此必须在构造函数中对这些属性初始化,否则编译不通过。
  • 可是以上属性值分为必选可选,所以构造函数需要提供不同的参数组合的方法。(即可选参数可以忽略)


方案一:

因此,综上两个前提,最直接的一个方案是定义多个重载的构造函数,其中一个构造函数只接收必选参数,其余的构造函数不仅要接收必选参数,还要接收不同可选参数的组合,代码如下:

public class User {    private final String mName;     //必选    private final String mGender;   //可选    private final int mAge;         //可选    private final String mPhone;    //可选    public User(String mName) {        this(mName, "");    }    public User(String mName,String mGender) {        this(mName, mGender, 0);    }    public User(String mName, String mGender, int mAge) {        this(mName, mGender, mAge, "");    }    public User(String mName, String mGender, int mAge, String mPhone) {        this.mName = mName;        this.mGender = mGender;        this.mAge = mAge;        this.mPhone = mPhone;    }}

这种构造函数的方式虽然简单,但是 只适用于少量属性的情况,一旦属性增多,构造函数的数量也会随着线性增长,因此并不好阅读及维护。



方案二:

第二种方案是遵循 JavaBeans 规范,定义一个默认的无参数构造函数,并为类的每个属性都提供getters 和 setters函数,代码如下:

public class User {    private String mName;     //必选    private String mGender;   //可选    private int mAge;         //可选    private String mPhone;    //可选    public String getName() {        return mName;    }    public void setName(String mName) {        this.mName = mName;    }    public String getGender() {        return mGender;    }    public void setGender(String mGender) {        this.mGender = mGender;    }    public int getAge() {        return mAge;    }    public void setAge(int mAge) {        this.mAge = mAge;    }    public String getPhone() {        return mPhone;    }    public void setPhone(String mPhone) {        this.mPhone = mPhone;    }}

这种方案相较于第一种方案的好处是易于阅读和维护,使用者可以创建一个空实例User,并只设置需要的属性值,可是此方案有两个缺点:

  • User类是可变的,禁锢了对象的可变性。
  • User类的实例状态不连续。如果想要创建一个同时具有所有属性的类实例,那么直到第五个属性值的 set函数被调用时,该类实例才具有完整连续的状态。这也就意味着类的调用者可能会看到类实例的不连续状态。


方案三: ☆☆☆☆☆

了解了以上两种比较常见但是效果却不太理想的方案后,正式引出第三种方案 —— 进化后的 Builder模式,既有以上两种方案的优点,又摒弃它们的缺点。代码如下:

public class User {    private final String mName;     //必选    private final String mGender;   //可选    private final int mAge;         //可选    private final String mPhone;    //可选    public User(UserBuilder userBuilder) {        this.mName = userBuilder.name;        this.mGender = userBuilder.gender;        this.mAge = userBuilder.age;        this.mPhone = userBuilder.phone;    }    public String getName() {        return mName;    }    public String getGender() {        return mGender;    }    public int getAge() {        return mAge;    }    public String getPhone() {        return mPhone;    }    public static class UserBuilder{        private final String name;             private String gender;           private int age;                 private String phone;        public UserBuilder(String name) {            this.name = name;        }        public UserBuilder gender(String gender){            this.gender = gender;            return this;        }        public UserBuilder age(int age){            this.age = age;            return this;        }        public UserBuilder phone(String phone){            this.phone = phone;            return this;        }        public User build(){            return new User(this);        }       }}

从以上代码可以看出这几点:

  • User类的构造函数是私有的,这意味着调用者不可直接实例化这个类。
  • User类是不可变的,其中必选的属性值都是 final 的并且在构造函数中设置;同时对所有的属性取消 setters函数,只保留 getter函数。
  • UserBuilder 的构造函数只接收必选的属性值作为参数,并且只是将必选的属性设置为 fianl来保证它们在构造函数中设置。

接下来,User类的使用方法如下:

    public User getUser(){        return new                User.UserBuilder("gym")                .gender("female")                .age(20)                .phone("12345678900")                .build();    }

以上通过 进化的Builder模式形象的体现在User的实例化。






三. AS 中自动生成 变化Builder模式

分析比较了以上三个方案后,也学习了解了 化Builder模式的好处和运用方法,可是你会发现它需要编写很多样板代码,需要在内部类 UserBuilder 中重复外部类User的属性定义。其实在AS中,可以通过安装 InnerBuilder 的插件来简化 Builder模式的创建过程,以下为安装使用步骤:


1. 在File菜单下打开 settings 选项,点开Plugins。

Android : Builder模式 详解及学习使用_第1张图片


2. 在中间的输入框输入 Builder 点击搜索,安装后根据提示重开AS即可。

Android : Builder模式 详解及学习使用_第2张图片


3. 在编写User类时,只需要把属性名确定下来,然后鼠标右键打开Generate菜单,选择 Builder按钮,在弹出的Builder配置对话框中进行相关配置的勾选,如下:

Android : Builder模式 详解及学习使用_第3张图片


完成以上步骤后,即可自动生成 进化Builder模式 代码,可能稍有不同,根据自身需求修改即可。






四. 开源函数库的例子

正如开头所说,Builder模式 被广泛运用于Android中的各个领域,无论是Android SDK 或各种开元函数库中,接下来关于Builder模式的运用举几个例子:


1. Android系统对话框 AlertDialog 的使用

    AlertDialog alertDialog = new AlertDialog.Builder(this).            setTitle("标题").            setMessage("内容").            setIcon(R.drawable.ic_logo).            create();    alertDialog.show();

2.网络请求框架 OkHttp 的请求封装:

private Request(Builder builder){    this.url = builder.url;    this.method = builder.method ;    this.headers = builder.headers.build() ;    this.body = builder.body ;    this.tag = builder.tag != null ? builder.tag : this;}

3. 图片缓存函数库 Android-Universal-Image-Loader 的全局配置也运用到了,在此不再举例了。






其实以上内容几乎都是书上的,前几天读到了这一章内容,讲的十分浅显易懂,之前自己没怎么理解这块内容,趁这次机会详细学习了一遍,以上内容及代码均手码出来,包括安装插件,亲自动手实践学习理解更深,在此谢过 顾浩鑫coder。

希望对你有帮助 :)

更多相关文章

  1. Android属性动画—实现第三方登录的上拉展开,下拉隐藏
  2. Android xml application属性详解
  3. RelativeLayout部分属性介绍
  4. android中自定义控件的属性
  5. Android的事件处理模式
  6. 如何设置Android 系统的属性,Build.prop, defualt.prop
  7. Android NDK开发——操作JNI函数以及复杂对象的传递
  8. Android中allowBackup属性的含义和危险性实例讲解

随机推荐

  1. 一个Android动态权限的流式权限管理库Eas
  2. Android(安卓)程序分析环境搭建-静态分析
  3. Android(安卓)EventBus3.1.1从使用到源码
  4. Android中常用shell命令详解
  5. android之socket编程实例一
  6. android hal层 c 堆栈打印方法
  7. Android(安卓)设备 USB 通用调试驱动的安
  8. Android简单实现仿微信选择图片以及拍照(P
  9. Handler发送消息后消息队列的处理
  10. Jenkins奇技淫巧 — 环境配置篇(Android