静态工厂和够构造器有一个共同的局限性:遇到大量的参数时无法很好的扩展。

先说说构造器。
其实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也有缺点。

  1. 创建实例前都要创建一个Builder实例。
  2. Builder模式编写起来较为冗长。

但是,当构建一个实例需要很多步骤(或者很多让人混淆的参数)的时候,Builder模式是个不错的选择。

Java - 用builder代替构造器的更多相关文章

  1. Builgen 插件——IntelliJ IDEA和Eclipse Java Bean Builder模式代码生成器-比lombok更符合需求

    builder模式在越来越多的项目中使用,类似于alibaba fastjson JSONObject.fluentPut(),调用一个方法后返回这个对象本身,特别适合构建一些参数超级多的对象,代码优 ...

  2. Atitti.java exp ast java表达式语法ast构造器

    Atitti.java exp ast java表达式语法ast构造器 /atiplat_cms/src/com/attilax/lang/AstParser.java 原理 分割tokens_sli ...

  3. java基础篇 之 构造器内部的多态行为

    java基础篇 之 构造器内部的多态行为 ​ 我们来看下下面这段代码: public class Main { public static void main(String[] args) { new ...

  4. 《Effective Java》-——用私有构造器或者枚举类型强化Singleton属性

    Singleton指仅仅被实例化一次的类.Singleton通常被用来代表那些本质上唯一的系统组件,比如窗口管理器或者文件系统.使类成为Singleton会使它的客户端测试变得十分困难,因为无法给Si ...

  5. Java设计模式-Builder构造者模式

    介绍: 构造者模式,又称之为建造者模式,建造者模式,单例模式以及工厂模式都属于创建型模式1应用场景 今天学mybatis的时候,知道了SQLSessionFactory使用的是builder模式来生成 ...

  6. java新手笔记10 构造器

    1.摇奖小程序 package com.yfs.javase; import java.io.IOException; import java.nio.CharBuffer; import java. ...

  7. java的三种构造器

    重叠构造器:不可取: javabeans模式:不可取: Builder模式:可取.

  8. 关于Java中基类构造器的调用问题

    在<Java编程思想>第7章复用类中有这样一段话,值得深思.当子类继承了父类时,就涉及到了基类和导出类(子类)这两个类.从外部来看,导出类就像是一个与基类具有相同接口的新类,或许还会有一些 ...

  9. Java之Builder模式(并用OC实现了这种模式)

    本人在学习Java,直接先学习Netty框架,因为Netty框架是业界最流行的NIO框架之一,在学习的过程中,了解到Netty服务端启动需要先创建服务器启动辅助类ServerBootstrap,它提供 ...

随机推荐

  1. [网络流24题][CTSC1999] 家园

    题目链接:戳我 对于这种一个点(表面意义上的一个点,比如说一个位置)对应多种情况的(比如说随着时间的推移有着不同的状态,而且这种状态>2),我们考虑在类似于分层图上面跑网络流. 比如说这道题,周 ...

  2. Windows系统下安装 CMake

    在安装caffe框架的时候需要用到cmake,特将cmake的安装总结如下: 1 什么是cmake CMake是一个跨平台的编译(Build)工具,可以用简单的语句来描述所有平台的编译过程.CMake ...

  3. IO模型《三》非阻塞IO

    非阻塞IO(non-blocking IO) Linux下,可以通过设置socket使其变为non-blocking.当对一个non-blocking socket执行读操作时,流程是这个样子: 从图 ...

  4. bzoj 3669: [Noi2014]魔法森林(并查集+LCT)

    Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M.初始时小E同学在号节 ...

  5. uC/OS-II 函数之OSInit()

    获得更多资料欢迎进入我的网站或者 csdn或者博客园 对于有热心的小伙伴在微博上私信我,说我的uC/OS-II 一些函数简介篇幅有些过于长应该分开介绍.应小伙伴的要求,特此将文章分开进行讲解.本文主要 ...

  6. replace函数结合正则表达式实现转化成驼峰与转化成连接字符串的方法

    //连接符转成驼峰写法 function toCamel(str){ var reg=/-(\w)/g; return str.replace(reg,function(){ return argum ...

  7. Flink学习笔记:Time的故事

    本文为<Flink大数据项目实战>学习笔记,想通过视频系统学习Flink这个最火爆的大数据计算框架的同学,推荐学习课程: Flink大数据项目实战:http://t.cn/EJtKhaz ...

  8. POJO和Javabean的区别:

    pojo:存粹java类,不继承,不实现.(不受限制的java类),多用于指数据库的映射对象javaBean:可复用组件,由容器(tomcat)创建,因此应具有无参构造器,不能跨进程访问,通常要无方法 ...

  9. [spring] Ioc 基础

    Ioc的理解:调用类对某一接口的实现类的依赖关系又第三方注入,以移除调用类对接口实现类的依赖.又叫做依赖注入.调用者对接口的选择权利被剥夺,交给了第三方.举个例子,学生本来可以选择哪个老师给他上课的, ...

  10. UVA-10929-You can say 11(秦九昭算法+同余与模算术)

    原题链接 1000位大数取余: 秦九昭算法+同余与模算术: 1314 = (((1)*10+3)*10+1)*10+4 ( a + b ) % n = ( ( a % n ) + ( b % n ) ...