在此声明:以下内容由书籍 《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;@Overridepublic void buildPartOne() {   }@Overridepublic void buildPartTwo() {}@Overridepublic Product getProduct() {return product;}
}
public class ConcreteBuilderB implements Builder {private Product product;@Overridepublic void buildPartOne() {   }@Overridepublic void buildPartTwo() {}@Overridepublic 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 newUser.UserBuilder("gym").gender("female").age(20).phone("12345678900").build();}

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






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

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


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


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


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


完成以上步骤后,即可自动生成 进化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。

希望对你有帮助 :)

Android : Builder模式 详解及学习使用相关推荐

  1. 2022最新Android面试题目解答,Android MVP模式详解

    开头 Android开发,假如开始没有任何的开发经验的话, 千万不要着急,不要想着在短时间内就把一个语言学习好, 因为你之前没有任何的学习经验, 在这个过程中需要有耐心地学习完JAVA的基础知识, 然 ...

  2. Android启动模式详解

    "在整理完启动模式后,我发现大家对启动模式的理解是有误区的" 引言 再谈启动模式,貌似没啥意思.但是你能正确回答下面的问题吗? 问题1:singleTask启动模式,在启动新的Ac ...

  3. Android  Doze and App Standby模式详解

    Android  Doze and App Standby模式详解 来源:腾云阁 https://www.qcloud.com/community Optimizing for Doze and Ap ...

  4. Android系统(187)---最易懂的Activity启动模式详解

    Android基础:最易懂的Activity启动模式详解 前言 Android基础中,Activity的启动模式非常重要 本文将全面介绍 Activity的启动模式 目录 目录 1. 定义 即Acti ...

  5. Android学习笔记——Android 签名机制详解

    Android 签名机制详解 近期由于工作需要在学习 Android 的签名机制,因为没有现成资料,只能通过开发者文档和阅读博客的方式对 Android 签名机制进行大致了解.过程中查阅到的资料相对零 ...

  6. Android M新特性Doze and App Standby模式详解

    转载请标明出处:http://blog.csdn.net/xx326664162/article/details/52312122 文章出自:薛瑄的博客 你也可以查看我的其他同类文章,也会让你有一定的 ...

  7. Android SystemUI 架构详解

    Android SystemUI 架构详解 本文描述Android系统中一个核心应用SystemUI,详细赘述SystemUI中几大模块功能的实现过程.由于作者水平有限,如发现本文中错误的地方,欢迎指 ...

  8. Android Studio 插件开发详解三:翻译插件实战

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/78113868 本文出自[赵彦军的博客] 系列目录 Android Gradle使用 ...

  9. Android OkHttp 全面详解

    Android OkHttp 全面详解 包的导入 基本使用 异步请求 同步请求 build创建 源码跟踪 newCall RealCall.enqueue Dispatcher.enqueue exe ...

最新文章

  1. JavaScript初学者编程题(5)
  2. 《移动数据挖掘》—— 第1章 引言 1.1 移动数据及其价值
  3. 批量ping 查看主机能否ping通,能否ssh上.md,
  4. 跨域调用报表展现页面的flash打印方法
  5. xcode5.0打包IPA
  6. Java并发编程实战~Condition
  7. HNU 实验五 拜访朋友
  8. Python变量的下划线
  9. linux删除eth2设备_Linux卸载/删除多余网卡
  10. 群体智能优化算法之狩猎搜索(Hunting Search,Hus)
  11. html中放大镜案列,HTML放大镜的一种实现及原理讲解(js)
  12. Python --- Numpy 创建n维数组基本方法
  13. 二维数组调时候的传参问题 and 一维数组的中括号秘密( [ ] )——实参与形参的对应 —————— 开开开山怪
  14. cobbler源码安装
  15. echarts折线图鼠标移入页面出现抖动
  16. Excel技巧:合并单元格后分组排序
  17. C++ accumulate()的使用
  18. VK11\VK12\VK13 价格间隔拆分问题
  19. 名编辑电子杂志大师教程 | 如何用名编辑制作一本精美的在线电子杂志?
  20. 在线传单制作工具介绍

热门文章

  1. Flac3D通过fish实现(位移)测线功能
  2. IC读卡器留下的dll坑0x000007b
  3. mysql报错 specify target table
  4. Nvidia Tesla和Quadro、GeForce的区别
  5. 0.91寸oled(128x32)的滚动显示问题
  6. Windows服务器配置与管理动态磁盘技术 、建立基本卷、带区卷、跨区卷、镜像卷和RAID-5卷的方法 磁盘配额...
  7. 虫洞协议背后的BCH“自我”之路
  8. executeBatch批量处理问题
  9. meshgrid用法
  10. java游戏英雄_【技巧攻略】教你用JAVA来玩《百万英雄》答题~