博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
11、【设计模式】构建器模式
阅读量:5122 次
发布时间:2019-06-13

本文共 5043 字,大约阅读时间需要 16 分钟。

一、引言

在日常的开发中,我们可能经常能看到如下的代码:

PrivateKeyDecryptParam param = new PrivateKeyDecryptParam.Builder().uAppId(uAppId).containerId(containerId).cipher(cipher).signFlag(signFlag).build();

  

在Android中,也会看到下面创建AlertDialog代码:

new AlertDialog.Builder(this).setTitle("标题").setMessage("内容").setCancelable(true).setOnCancelListener(new DialogInterface.OnCancelListener() {@Overridepublic void onCancel(DialogInterface dialog) {}}).show();

  

观察上面这两段代码,都有一个共同的特点,就是都可以进行链式操作,这就是我们要学习的Builder模式,下面就来详细学习一下。

二、Builer模式的使用场景

在《Effective Java第2版》书中有提到,当遇到多个构造器参数时,要考虑使用构建器(Builder模式)。

举个例子,比如在项目中,我们需要新建一个Person类,假设该类有7个属性(现实中远不止这几个参数),其中有2个是必要的参数需要初始化,分别是id和name。

1、使用JavaBean的setter方法来设置对象属性

最常见的写法应该是写成JavaBean。代码如下:

public class Person {//必要参数private int id;private String name;//可选参数private int age;private String sex;private String phone;private String address;private String desc;public void setId(int id) {this.id = id;}public void setName(String name) {this.name = name;}public void setAge(int age) {this.age = age;}public void setSex(String sex) {this.sex = sex;}public void setPhone(String phone) {this.phone = phone;}public void setAddress(String address) {this.address = address;}public void setDesc(String desc) {this.desc = desc;}}

  

在使用该Person类的时候,会写出如下的代码:

Person person = new Person();person.setId(1);person.setName("张小毛");person.setAge(22);person.setSex("男");person.setPhone("19999999999");person.setAddress("beijing");person.setDesc("JavaBeans模式");

  

这种JavaBean的方式也是常见的构造对象并赋值的方式,这种方式的好处是:

(1)、易于阅读,并且可以只对有用的成员变量赋值;

但它的缺点是:

(1)、成员变量不可以是 final 类型,失去了不可变对象的很多好处;

(2)、对象状态不连续,你必须调用7次setter方法才能得到一个具备7个属性值得变量,在这期间用户可能拿到不完整状态的对象。如果有N个属性,岂不是要person.setXXX调用N次?此种方式不优雅。

最重要的缺点是第二条:对象状态不连续。什么意思呢?

解释一下:这种方式是 先创建对象、后赋值,用户不知道什么时候拿到的对象是完整的,构建完成的。很有可能你只setter了一两个属性就返回了,一些必要的属性没有被赋值。

2、使用重叠构造器

在这种模式下,需要提供一个只有必要参数的构造器,第二个构造器有一个可选参数,第三个有两个可选参数,依此类推,最后一个构造器包含所有的可选参数。代码如下:

public class Person {//必要参数private final int id;private final String name;//可选参数private int age;private String sex;private String phone;private String address;private String desc;public Person(int id, String name) {this(id, name, 0);}public Person(int id, String name, int age) {this(id, name, age, "");}public Person(int id, String name, int age, String sex) {this(id, name, age, sex, "");}public Person(int id, String name, int age, String sex, String phone) {this(id, name, age, sex, phone, "");}public Person(int id, String name, int age, String sex, String phone, String address) {this(id, name, age, sex, phone, address, "");}public Person(int id, String name, int age, String sex, String phone, String address, String desc) {this.id = id;this.name = name;this.age = age;this.sex = sex;this.phone = phone;this.address = address;this.desc = desc;}}

  

从上面的代码可以看出,当你想要创建实例的时候,就利用参数列表最短的构造器,但该列表中包含了要设置的所有参数,其余都为默认值:

Person person = new Persion(1, "张小毛");

1
这个构造器调用,通常需要许多你本不想设置的参数,但还是不得不为它们传递值。

这种方式的优点就是:简单!!!!(这是对开发者而言),但使用者在使用时,可得仔细了解你每个构造函数,否则一不小心填错顺序也不知道。而且如果有十几个属性,就歇菜了……(我也没见过有十几个参数的构造函数)

所以缺点是:

只适用于成员变量少的情况,太多了不容易理解、维护。

简而言之:重叠构造器可行,但是当有许多参数的时候,创建使用代码会很难写,并且较难以阅读。

三、变种Builder模式

对于上述分析的两种方法,都存在优点和缺点,为了解决上述两种构建方式的不足,伟大的程序员们创造出了变种 Builder模式。直接看代码:

public class Person {//必要参数private final int id;private final String name;//可选参数private int age;private String sex;private String phone;private String address;private String desc;private Person(Builder builder) {this.id = builder.id;this.name = builder.name;this.age = builder.age;this.sex = builder.sex;this.phone = builder.phone;this.address = builder.address;this.desc = builder.desc;}public static class Builder {//必要参数private final int id;private final String name;//可选参数private int age;private String sex;private String phone;private String address;private String desc;public Builder(int id, String name) {this.id = id;this.name = name;}public Builder age(int val) {this.age = val;return this;}public Builder sex(String val) {this.sex = val;return this;}public Builder phone(String val) {this.phone = val;return this;}public Builder address(String val) {this.address = val;return this;}public Builder desc(String val) {this.desc = val;return this;}public Person build() {return new Person(this);}}}

  

观察上述代码,可以看到变种Builder模式包括以下内容:

(1)、在要构建类的内部,创建一个静态内部类Builder;

(2)、静态内部类的属性要与构建类的属性一致;

(3)、构建类的构造参数是静态内部类,使用静态内部类的变量为构建类逐一赋值;

(4)、静态内部类提供参数的setter方法,并且返回值是当前Builder对象;

(5)、最终提供一个build方法new出来一个构建类的对象,参数是当前Builder对象;

调用代码如下:

public class Test {public static void main(String[] args) {        Person person = new Person.Builder(1, "张小毛")            .age(22).sex("男").desc("使用builder模式").build();        System.out.println(person.toString());    }}

  

对变种Builer模式的总结:

(1)、变种Builder模式目的在于:减少对象创建过程中引入的多个构造函数、可选参数以及多个setter过度使用导致的不必要的复杂性。

(2)、优点就是:看起来很整齐;先赋值,后创建对象,最终调用build()方法才创建了构建类的对象,保证了状态的完整性。

(3)、缺点嘛,就是需要额外写的代码多了点。

四、总结:

变种Builer模式相比于重叠构造器模式和JavaBeans模式,Builder模式实现的对象更利于使用。

对Builer模式使用方法的总结:

(1)、外部类的构造函数私有,且参数为静态内部类;
(2)、静态内部类拥有外部类相同的属性;
(3)、为每一个属性,写一个方法,返回的是Builer;
(4)、最后一个方法是build方法,用于构建一个外部类;

转自:https://blog.csdn.net/zxd1435513775/article/details/83016670 

转载于:https://www.cnblogs.com/itplay/p/11186932.html

你可能感兴趣的文章
VMware Tools安装
查看>>
Linux上架设boost的安装及配置过程
查看>>
[转载]加密算法库Crypto——nodejs中间件系列
查看>>
zoj 2286 Sum of Divisors
查看>>
OO5~7次作业总结
查看>>
使用Xshell密钥认证机制远程登录Linux
查看>>
OpenCV之响应鼠标(三):响应鼠标信息
查看>>
Android 画图之 Matrix(一)
查看>>
List<T>列表通用过滤模块设计
查看>>
【模板】最小生成树
查看>>
设计模式之结构型模式
查看>>
poj2569
查看>>
使用pygal_maps_world.i18n中数据画各大洲地图
查看>>
sql server必知多种日期函数时间格式转换
查看>>
jQuery EasyUI 的下拉选择combobox后台动态赋值
查看>>
timeline时间轴进度“群英荟萃”
查看>>
python if else elif statement
查看>>
网络编程
查看>>
文本隐藏(图片代替文字)
查看>>
java面试题
查看>>