Java - 用builder代替构造器
静态工厂和够构造器有一个共同的局限性:遇到大量的参数时无法很好的扩展。
先说说构造器。
其实field不多时重叠构造器(telescoping constructor)是个不错的方法,易于编写也易于调用,这种方式在参数数量较少时也很常见。
但问题是参数很多(可能越来越多)时,比如(现在已经很难找到对多个参数进行重叠构造的代码了,于是在这里直接引用一下书中的代码):
public class NutritionFacts {
private final int servingSize; // (mL) required
private final int servings; // (per container) required
private final int calories; // optional
private final int fat; // (g) optional
private final int sodium; // (mg) optional
private final int carbohydrate; // (g) optional
public NutritionFacts(int servingSize, int servings) {
this(servingSize, servings, 0);
}
public NutritionFacts(int servingSize, int servings, int calories) {
this(servingSize, servings, calories, 0);
}
public NutritionFacts(int servingSize, int servings, int calories, int fat) {
this(servingSize, servings, calories, fat, 0);
}
public NutritionFacts(int servingSize, int servings, int calories, int fat,
int sodium) {
this(servingSize, servings, calories, fat, sodium, 0);
}
public NutritionFacts(int servingSize, int servings, int calories, int fat,
int sodium, int carbohydrate) {
this.servingSize = servingSize;
this.servings = servings;
this.calories = calories;
this.fat = fat;
this.sodium = sodium;
this.carbohydrate = carbohydrate;
}
}
我想创建实例的时候,代码会变成这个样子:
public static void main(String[] args) {
NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27);
}
为了让创建实例的过程变得更加清晰,于是我们有另一中选择——JavaBean模式。
这个再熟悉不过了,如下:
public class NutritionFacts {
// Parameters initialized to default values (if any)
private int servingSize = -1;
private int servings = -1;
private int calories = 0;
private int fat = 0;
private int sodium = 0;
private int carbohydrate = 0;
public NutritionFacts() {
}
// Setters
public void setServingSize(int val) {
servingSize = val;
}
public void setServings(int val) {
servings = val;
}
public void setCalories(int val) {
calories = val;
}
public void setFat(int val) {
fat = val;
}
public void setSodium(int val) {
sodium = val;
}
public void setCarbohydrate(int val) {
carbohydrate = val;
}
}
用起来虽然比只有一行的构造器多几个步骤,但非常清晰:
public static void main(String[] args) {
NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohydrate(27);
}
相比只通过一个构造器创建实例,JavaBean模式的实例的构造过程被分成了好几个过程。
我们完全有可能在属性不完整的情况下使用这个实例。
按书中原文就是:
A JavaBean may be in a inconsistent state partway through its construction.
当然,我们也可以做一些操作使其在未完成的情况下无法使用,但我不想因此让一个类变得越来越复杂。
另外,我根本无法用JavaBean模式完全排除了将类设计成不可变(Immutable)的可能性。
此时,我们选择使用Builder来解决这一问题。
示例如下:
public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;
public static class Builder {
// Required parameters
private final int servingSize;
private final int servings;
// Optional parameters - initialized to default values
private int calories = 0;
private int fat = 0;
private int carbohydrate = 0;
private int sodium = 0;
public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
public Builder calories(int val) {
calories = val;
return this;
}
public Builder fat(int val) {
fat = val;
return this;
}
public Builder carbohydrate(int val) {
carbohydrate = val;
return this;
}
public Builder sodium(int val) {
sodium = val;
return this;
}
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
private NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
}
调用起来非常清晰(模拟了具名参数),而且非常简单:
public static void main(String[] args) {
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8)
.calories(100).sodium(35).carbohydrate(27).build();
}
当然,Builder也有缺点。
- 创建实例前都要创建一个Builder实例。
- Builder模式编写起来较为冗长。
但是,当构建一个实例需要很多步骤(或者很多让人混淆的参数)的时候,Builder模式是个不错的选择。
Java - 用builder代替构造器的更多相关文章
- Builgen 插件——IntelliJ IDEA和Eclipse Java Bean Builder模式代码生成器-比lombok更符合需求
builder模式在越来越多的项目中使用,类似于alibaba fastjson JSONObject.fluentPut(),调用一个方法后返回这个对象本身,特别适合构建一些参数超级多的对象,代码优 ...
- Atitti.java exp ast java表达式语法ast构造器
Atitti.java exp ast java表达式语法ast构造器 /atiplat_cms/src/com/attilax/lang/AstParser.java 原理 分割tokens_sli ...
- java基础篇 之 构造器内部的多态行为
java基础篇 之 构造器内部的多态行为 我们来看下下面这段代码: public class Main { public static void main(String[] args) { new ...
- 《Effective Java》-——用私有构造器或者枚举类型强化Singleton属性
Singleton指仅仅被实例化一次的类.Singleton通常被用来代表那些本质上唯一的系统组件,比如窗口管理器或者文件系统.使类成为Singleton会使它的客户端测试变得十分困难,因为无法给Si ...
- Java设计模式-Builder构造者模式
介绍: 构造者模式,又称之为建造者模式,建造者模式,单例模式以及工厂模式都属于创建型模式1应用场景 今天学mybatis的时候,知道了SQLSessionFactory使用的是builder模式来生成 ...
- java新手笔记10 构造器
1.摇奖小程序 package com.yfs.javase; import java.io.IOException; import java.nio.CharBuffer; import java. ...
- java的三种构造器
重叠构造器:不可取: javabeans模式:不可取: Builder模式:可取.
- 关于Java中基类构造器的调用问题
在<Java编程思想>第7章复用类中有这样一段话,值得深思.当子类继承了父类时,就涉及到了基类和导出类(子类)这两个类.从外部来看,导出类就像是一个与基类具有相同接口的新类,或许还会有一些 ...
- Java之Builder模式(并用OC实现了这种模式)
本人在学习Java,直接先学习Netty框架,因为Netty框架是业界最流行的NIO框架之一,在学习的过程中,了解到Netty服务端启动需要先创建服务器启动辅助类ServerBootstrap,它提供 ...
随机推荐
- UML uml建模工具
UML建模工具 一.UML的概念: 参考百度百科: https://baike.baidu.com/item/%E7%BB%9F%E4%B8%80%E5%BB%BA%E6%A8%A1%E8%AF%AD ...
- Template 动画
如果设置Template的动画,也就意味着对每一个具有此Template的对象进行动画处理. 比如对ListBoxI的ItemTemplate进行设置,添加动画,触发器等,每一个ListBoxItem ...
- 526. Beautiful Arrangement
Suppose you have N integers from 1 to N. We define a beautiful arrangement as an array that is const ...
- luoguP4755 Beautiful Pair
https://www.luogu.org/problemnew/show/P4755 考虑分治,在 [l, r] 区间中用线段树找到最大的一个点,处理经过它的可行数对的个数,统计个数可以离线树状数组 ...
- 各种 Python 库/模块/工具
1 算法 1.1 字符串处理 re 正则表达式的标准库. StringIO / cStringIO 以读写文件的方式来操作字符串(有点类似于内存文件). cStringIO 是 C 语言实现的,提供高 ...
- [转]IOS应用程序多语言本地化解决方案
最近要对一款游戏进行多语言本地化,在网上找了一些方案,加上自己的一点点想法整理出一套方案和大家分享! 多语言在应用程序中一般有两种做法:一.程序中提供给用户自己选择的机会:二.根据当前用户当前移动设备 ...
- anaconda安装出现failed to create anacoda menue
1.卸载Anaconda后重新安装Anaconda出现各种问题,粗暴解决方式:直接将安装目录放在C盘主路径下,完美解决. 2.然后无选择忽略,忽略,忽略,提示安装成功,依旧没有 菜单 进入 cmd,找 ...
- 经典C面试真题精讲
第一章 灵魂--指针 101. p++ 请分析下述代码的输出结果 int main() { char* p1 = "China"; char* p2, * p3; p2 = (); ...
- 2.使用ngx_http_auth_basic_module模块为不带认证的资源添加授权
1.首先需要生成用户名和密码 使用openssl来生成,生成命令(openssl在安装nginx的时候已经安装) echo "kibana:$(openssl passwd -crypt y ...
- oracle mysql的序列的新增、删除、修改及使用
序列的使用 参考文献: https://blog.csdn.net/meijory/article/details/51891529 1.序列介绍 序列: 是 oracle 提供的用于产生一系列唯一 ...