Android : Builder模式 详解及学习使用
在此声明:以下内容由书籍 《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模式 详解及学习使用相关推荐
- 2022最新Android面试题目解答,Android MVP模式详解
开头 Android开发,假如开始没有任何的开发经验的话, 千万不要着急,不要想着在短时间内就把一个语言学习好, 因为你之前没有任何的学习经验, 在这个过程中需要有耐心地学习完JAVA的基础知识, 然 ...
- Android启动模式详解
"在整理完启动模式后,我发现大家对启动模式的理解是有误区的" 引言 再谈启动模式,貌似没啥意思.但是你能正确回答下面的问题吗? 问题1:singleTask启动模式,在启动新的Ac ...
- Android Doze and App Standby模式详解
Android Doze and App Standby模式详解 来源:腾云阁 https://www.qcloud.com/community Optimizing for Doze and Ap ...
- Android系统(187)---最易懂的Activity启动模式详解
Android基础:最易懂的Activity启动模式详解 前言 Android基础中,Activity的启动模式非常重要 本文将全面介绍 Activity的启动模式 目录 目录 1. 定义 即Acti ...
- Android学习笔记——Android 签名机制详解
Android 签名机制详解 近期由于工作需要在学习 Android 的签名机制,因为没有现成资料,只能通过开发者文档和阅读博客的方式对 Android 签名机制进行大致了解.过程中查阅到的资料相对零 ...
- Android M新特性Doze and App Standby模式详解
转载请标明出处:http://blog.csdn.net/xx326664162/article/details/52312122 文章出自:薛瑄的博客 你也可以查看我的其他同类文章,也会让你有一定的 ...
- Android SystemUI 架构详解
Android SystemUI 架构详解 本文描述Android系统中一个核心应用SystemUI,详细赘述SystemUI中几大模块功能的实现过程.由于作者水平有限,如发现本文中错误的地方,欢迎指 ...
- Android Studio 插件开发详解三:翻译插件实战
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/78113868 本文出自[赵彦军的博客] 系列目录 Android Gradle使用 ...
- Android OkHttp 全面详解
Android OkHttp 全面详解 包的导入 基本使用 异步请求 同步请求 build创建 源码跟踪 newCall RealCall.enqueue Dispatcher.enqueue exe ...
最新文章
- JavaScript初学者编程题(5)
- 《移动数据挖掘》—— 第1章 引言 1.1 移动数据及其价值
- 批量ping 查看主机能否ping通,能否ssh上.md,
- 跨域调用报表展现页面的flash打印方法
- xcode5.0打包IPA
- Java并发编程实战~Condition
- HNU 实验五 拜访朋友
- Python变量的下划线
- linux删除eth2设备_Linux卸载/删除多余网卡
- 群体智能优化算法之狩猎搜索(Hunting Search,Hus)
- html中放大镜案列,HTML放大镜的一种实现及原理讲解(js)
- Python --- Numpy 创建n维数组基本方法
- 二维数组调时候的传参问题 and 一维数组的中括号秘密( [ ] )——实参与形参的对应 —————— 开开开山怪
- cobbler源码安装
- echarts折线图鼠标移入页面出现抖动
- Excel技巧:合并单元格后分组排序
- C++ accumulate()的使用
- VK11\VK12\VK13 价格间隔拆分问题
- 名编辑电子杂志大师教程 | 如何用名编辑制作一本精美的在线电子杂志?
- 在线传单制作工具介绍
热门文章
- Flac3D通过fish实现(位移)测线功能
- IC读卡器留下的dll坑0x000007b
- mysql报错 specify target table
- Nvidia Tesla和Quadro、GeForce的区别
- 0.91寸oled(128x32)的滚动显示问题
- Windows服务器配置与管理动态磁盘技术 、建立基本卷、带区卷、跨区卷、镜像卷和RAID-5卷的方法 磁盘配额...
- 虫洞协议背后的BCH“自我”之路
- executeBatch批量处理问题
- meshgrid用法
- java游戏英雄_【技巧攻略】教你用JAVA来玩《百万英雄》答题~