了解了单例模式,接下来介绍另一个常见的模式——Builder模式。

那么什么是Builder模式呢。通过搜索,会发现大部分网上的定义都是

  1. 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

但是看完这个定义,依然不知道什么是Builder设计模式。不要过度在意其定义,定义往往是比较抽象的,学习它最好的例子就是通过样例代码。

我们通过一个例子来引出Builder模式。假设有一个Person类,我们通过该Person类来构建一大批人,这个Person类里有很多属性,最常见的比如name,age,weight,height等等,并且我们允许这些值不被设置,也就是允许为null,该类的定义如下。

  1. public class Person {
  2. private String name;
  3. private int age;
  4. private double height;
  5. private double weight;
  6. public String getName() {
  7. return name;
  8. }
  9. public void setName(String name) {
  10. this.name = name;
  11. }
  12. public int getAge() {
  13. return age;
  14. }
  15. public void setAge(int age) {
  16. this.age = age;
  17. }
  18. public double getHeight() {
  19. return height;
  20. }
  21. public void setHeight(double height) {
  22. this.height = height;
  23. }
  24. public double getWeight() {
  25. return weight;
  26. }
  27. public void setWeight(double weight) {
  28. this.weight = weight;
  29. }
  30. }

然后我们为了方便可能会定义一个构造方法。

  1. public Person(String name, int age, double height, double weight) {
  2. this.name = name;
  3. this.age = age;
  4. this.height = height;
  5. this.weight = weight;
  6. }

或许为了方便new对象,你还会定义一个空的构造方法

  1. public Person() {
  2. }

甚至有时候你很懒,只想传部分参数,你还会定义如下类似的构造方法。

  1. public Person(String name) {
  2. this.name = name;
  3. }
  4. public Person(String name, int age) {
  5. this.name = name;
  6. this.age = age;
  7. }
  8. public Person(String name, int age, double height) {
  9. this.name = name;
  10. this.age = age;
  11. this.height = height;
  12. }

于是你就可以这样创建各个需要的对象

  1. Person p1=new Person();
  2. Person p2=new Person("张三");
  3. Person p3=new Person("李四",18);
  4. Person p4=new Person("王五",21,180);
  5. Person p5=new Person("赵六",17,170,65.4);

可以想象一下这样创建的坏处,最直观的就是四个参数的构造函数的最后面的两个参数到底是什么意思,可读性不怎么好,如果不点击看源码,鬼知道哪个是weight哪个是height。还有一个问题就是当有很多参数时,编写这个构造函数就会显得异常麻烦,这时候如果换一个角度,试试Builder模式,你会发现代码的可读性一下子就上去了。

我们给Person增加一个静态内部类Builder类,并修改Person类的构造函数,代码如下。

  1. public class Person {
  2. private String name;
  3. private int age;
  4. private double height;
  5. private double weight;
  6. privatePerson(Builder builder) {
  7. this.name=builder.name;
  8. this.age=builder.age;
  9. this.height=builder.height;
  10. this.weight=builder.weight;
  11. }
  12. public String getName() {
  13. return name;
  14. }
  15. public void setName(String name) {
  16. this.name = name;
  17. }
  18. public int getAge() {
  19. return age;
  20. }
  21. public void setAge(int age) {
  22. this.age = age;
  23. }
  24. public double getHeight() {
  25. return height;
  26. }
  27. public void setHeight(double height) {
  28. this.height = height;
  29. }
  30. public double getWeight() {
  31. return weight;
  32. }
  33. public void setWeight(double weight) {
  34. this.weight = weight;
  35. }
  36. static class Builder{
  37. private String name;
  38. private int age;
  39. private double height;
  40. private double weight;
  41. public Builder name(String name){
  42. this.name=name;
  43. return this;
  44. }
  45. public Builder age(int age){
  46. this.age=age;
  47. return this;
  48. }
  49. public Builder height(double height){
  50. this.height=height;
  51. return this;
  52. }
  53. public Builder weight(double weight){
  54. this.weight=weight;
  55. return this;
  56. }
  57. public Person build(){
  58. return new Person(this);
  59. }
  60. }
  61. }

从上面的代码中我们可以看到,我们在Builder类里定义了一份与Person类一模一样的变量,通过一系列的成员函数进行设置属性值,但是返回值都是this,也就是都是Builder对象,最后提供了一个build函数用于创建Person对象,返回的是Person对象,对应的构造函数在Person类中进行定义,也就是构造函数的入参是Builder对象,然后依次对自己的成员变量进行赋值,对应的值都是Builder对象中的值。此外Builder类中的成员函数返回Builder对象自身的另一个作用就是让它支持链式调用,使代码可读性大大增强。

于是我们就可以这样创建Person类。

  1. Person.Builder builder=new Person.Builder();
  2. Person person=builder
  3. .name("张三")
  4. .age(18)
  5. .height(178.5)
  6. .weight(67.4)
  7. .build();

有没有觉得创建过程一下子就变得那么清晰了。对应的值是什么属性一目了然,可读性大大增强。

其实在Android中, Builder模式也是被大量的运用。比如常见的对话框的创建

  1. AlertDialog.Builder builder=new AlertDialog.Builder(this);
  2. AlertDialog dialog=builder.setTitle("标题")
  3. .setIcon(android.R.drawable.ic_dialog_alert)
  4. .setView(R.layout.myview)
  5. .setPositiveButton(R.string.positive, new DialogInterface.OnClickListener() {
  6. @Override
  7. public void onClick(DialogInterface dialog, int which) {
  8. }
  9. })
  10. .setNegativeButton(R.string.negative, new DialogInterface.OnClickListener() {
  11. @Override
  12. public void onClick(DialogInterface dialog, int which) {
  13. }
  14. })
  15. .create();
  16. dialog.show();

其实在java中有两个常见的类也是Builder模式,那就是StringBuilder和StringBuffer,只不过其实现过程简化了一点罢了。

我们再找找Builder模式在各个框架中的应用。

如Gson中的GsonBuilder,这里只贴出其Builder的使用方法。

  1. GsonBuilder builder=new GsonBuilder();
  2. Gson gson=builder.setPrettyPrinting()
  3. .disableHtmlEscaping()
  4. .generateNonExecutableJson()
  5. .serializeNulls()
  6. .create();

可见各大框架中大量的运用了Builder模式。最后总结一下

  • 定义一个静态内部类Builder,内部的成员变量和外部类一样
  • Builder类通过一系列的方法用于成员变量的赋值,并返回当前对象本身(this)
  • Builder类提供一个build方法或者create方法用于创建对应的外部类,该方法内部调用了外部类的一个私有构造函数,该构造函数的参数就是内部类Builder
  • 外部类提供一个私有构造函数供内部类调用,在该构造函数中完成成员变量的赋值,取值为Builder对象中对应的值

Android开发中常见的设计模式(二)——Builder模式的更多相关文章

  1. Android开发中常见的设计模式 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  2. Android开发中无处不在的设计模式——动态代理模式

    继续更新设计模式系列.写这个模式的主要原因是近期看到了动态代理的代码. 先来回想一下前5个模式: - Android开发中无处不在的设计模式--单例模式 - Android开发中无处不在的设计模式-- ...

  3. Android开发中常见的设计模式

    对于开发人员来说,设计模式有时候就是一道坎,但是设计模式又非常有用,过了这道坎,它可以让你水平提高一个档次.而在android开发中,必要的了解一些设计模式又是非常有必要的.对于想系统的学习设计模式的 ...

  4. Android开发中常见的设计模式(一)——单例模式

    首先了解一些单例模式的概念. 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 这样做有以下几个优点 对于那些比较耗内存的类,只实例化一次可以大大提高性能,尤其是在移动开发中. 保持 ...

  5. Android开发中常见的设计模式(四)——策略模式

    策略模式定义了一些列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式让算法独立于使用它的客户而独立变换. 假设我们要出去旅游,而去旅游出行的方式有很多,有步行,有坐火车,有坐飞机等等 ...

  6. Android开发中常见的设计模式(三)——观察者模式

    先看下这个模式的定义. 定义对象间的一种一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都能得到通知并被自动更新 先来讲几个情景. 情景1:有一种短信服务,比如天气预报服务,一旦你订阅 ...

  7. Android开发中常用的设计模式

    首先需要说明的是,这篇博文灵感来自于 http://www.cnblogs.com/qianxudetianxia/archive/2011/07/29/2121547.html ,在这里,博主已经很 ...

  8. Android 开发中常见的注意点

    这里总结了Android开发中常用的注意点.只有总结,没有展开举例讲解,展开的话,一个点都可以写一篇文章了..... 这类问题都一定不要犯. 重要的事情说三遍!!! 说三遍!!! 遍!!! 资源 不允 ...

  9. iOS 开发中常见的设计模式

    最近有小伙伴问到在iOS开发中的几种设计模式,这里摘录一下别人的总结(因为已经感觉总结得差不多了,适用的可以阅读一下) 首先是开发中的23中设计模式分为三大类:1.创建型 2.结构型 3.行为型 (i ...

随机推荐

  1. 禁止光盘优盘自动播放(Shell Hardware Detection服务)

    strComputer = "."Set objWMIService = GetObject("winmgmts:\\" & strComputer & ...

  2. windows下网络丢包模拟软件(Network Emulator for Windows Toolkit)

    最近公司有一个直播的测试项目,需要模拟各种网络环境下的直播状态,最后找到一款这样的软件(如果有遇到更好的软件,望和网友多多交流) 介绍一款windows下的网络模拟器,可以模拟各种丢包或延迟的网络(N ...

  3. Springboot配置使用ssl,使用https

    SSL(Secure Sockets Layer 安全套接层)是为网络通信提供安全及数据完整性的一种安全协议,SSL在网络传输层对网络连接进行加密,SSL协议位于TCP/IP协议与各种应用层协议之间, ...

  4. VRRP、Track与NQA联动配置举例(Master监视上行链路)

    原文 http://www.h3c.com/cn/d_201708/1018729_30005_0.htm#_Toc488338729 1. 组网需求 Host A需要访问Internet上的Host ...

  5. IGMP Internet组管理协议 未完

    一.IGMP Internet组管理协议 2.IGMP v2 3.IGMP三版本比较 4.1.1.4 IGMP v2 与 IGMP v1 的兼容 5.IGMP窃听(IGMP Snooping) IGM ...

  6. [UE4]枚举Enum和Switch Enum

  7. IBM MQ常用命令

    常用命令 创建队列管理器crtmqm –q QMgrName-q是指创建缺省的队列管理器删除队列管理器dltmqm QmgrName启动队列管理器strmqm QmgrName如果是启动默认的队列管理 ...

  8. Mybatis 系列3-结合源码解析properties节点和environments节点

    [Mybatis 系列10-结合源码解析mybatis 执行流程] [Mybatis 系列9-强大的动态sql 语句] [Mybatis 系列8-结合源码解析select.resultMap的用法] ...

  9. C/C++ 与 Python 的通信

    作者:Jerry Jho链接:https://www.zhihu.com/question/23003213/answer/56121859来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商 ...

  10. xgboost的sklearn接口和原生接口参数详细说明及调参指点

    from xgboost import XGBClassifier XGBClassifier(max_depth=3,learning_rate=0.1,n_estimators=100,silen ...