静态工厂和构造器有个共同的局限性:它们都不能很好地扩展到大量的可选参数。

  当一个类中有若干个必选属性和多个可选属性时,采用重叠构造器模式、JavaBeans模式或者Builder模式,但各有优劣。

  当有很多参数的时候,重叠构造器模式下客户端代码会很难编写,并且仍然较难以阅读。

  JavaBeans模式调用一个无参构造器来创建对象,然后调用setter方法来设置每个必要的参数,以及每个相关的可选参数。因为构造过程被分到了几个调用中,在构造过程中JavaBean可能处于不一致的状态。与此相关的另一点不足在于,JavaBeans模式阻止了把类做成不可变的可能。

  Builder模式不直接生成想要的对象,而是让客户端利用所有必要的参数调用构造器(或者静态工厂),得到一个builder对象,然后客户端在builder对象上调用类似于setter的方法,来设置每个相关的可选参数,客户端最后调用无参的build方法来生成不可变的对象。这个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域中对它们进行检验。如果违反了任何约束条件,build方法就应该抛出IllegalArgumentException。对多个参数强加约束条件的另一个方法是,用多个setter方法对某个约束条件必须持有的所有参数进行检查。一旦传递了无效的参数,立即就会发现约束条件失败,而不是等着调用build方法。与构造器相比,builder的微略优势在于,builder可以有多个可变参数。构造器就像方法一样,只能有一个可变参数。

  Java中传统的抽象工厂实现是Class对象,newInstance方法总是企图调用类的无参构造器,这个构造器甚至可能根本不存在。Class.newInstance破坏了编译时的异常检查。Builder模式也存在不足。为了创建对象,必须先创建它的构建器。在十分注重性能的情况下,可能就成问题了。Builder模式还比重叠构造器模式更加冗长,因此它只在有很多参数的时候才使用,比如4个或者更多个参数。通常最好一开始就使用构建器。

  如果类的构造器或者静态工厂中具有多个参数,设计这种类时,Builder模式就是种不错的选择,特别是当大多数参数都是可选的时候。与使用传统的重叠构造器模式相比,使用Builder模式的客户端代码将更易于阅读和编写,构建器也比JavaBeans更加安全。

  参考资料

  《Effective Java 中文版 第2版》 第2条:遇到多个构造器时要考虑用构建器 P9-13

Java 构造器 遇到多个构造器时要考虑用构建器的更多相关文章

  1. 【读书笔记 - Effective Java】02. 遇到多个构造器参数时要考虑用构建器

    类有多个可选参数的解决方案: 1. 重叠构造器模式可行,但是当有许多参数的时候,客户端代码会很难编写,并且仍然较难以阅读. 2. JavaBeans模式,调用一个无参构造器来创造对象,然后调用sett ...

  2. 链式编程:遇到多个构造器参数(Constructor Parameters)时要考虑用构建器(Builder)

    public class NutritionFacts { private final int servingSize; private final int servings; private fin ...

  3. 遇到多个构造器参数时要考虑用构建器 builder 模式 JavaBean 线程安全

    effective java p9 JavaBeans模式阻止了把类做成不可变的可能,这需要程序员付出额外的努力来确保它的线程安全.

  4. 解析《Effective Java》之多个构造器、Javabeans模式和Builder模式

    最近看<Effective Java>这本被很多同行称为神作的书,但是这本书很多地方缺少了举例不好懂,下面是关于我对书上知识的理解. 一.<Effective Java>中文版 ...

  5. Effective Java 之-----静态工厂与构造器

    一. 考虑用静态工厂方法代替构造器: 1)静态工厂方法与构造器不同的第一大优势在于:他们有名称.当一个类需要多个带有相同签名的构造器时,就用静态方法代替构造器,并慎重的选择名称以突出他们间的区别: 2 ...

  6. 构造器参数过多时考虑使用构建器(Builder)

    一.静态工厂和构造器的局限性 面对需要大量可选参数才能构建对象时,静态工厂和构造器并不能随着可选参数的增加而合理扩展. 假设创建一个类Person需要使用大量的可选参数,其中两个参数是必填的,剩下的都 ...

  7. effective java之使用构建器来创建对象

    第二章第2条:遇到多个构造器参数时要考虑使用构建器(builder) 就是建造者模式(不直接生成想要的对象,而是让客户端利用所有有必要的参数调用构造器或者静态工厂)直接上代码 package com. ...

  8. Java继承之再谈构造器

    目录 Java继承之再谈构造器 初始化基类 默认构造器 带参数的构造器 子类调用父类构造器 Java继承之再谈构造器 初始化基类 前面提到,继承是子类对父类的拓展.<Thinking in Ja ...

  9. Java构造器与构建器的使用

    我们在平常类的构建过程中,可能会面临很多问题,可扩张性.安全性等等.想象一下,这样一个场景,我们现在要创建一个类,其中有6个属性,其中又有4个属性的值是不太确定的(可能某个对象就不需要其中的某个值), ...

随机推荐

  1. SQLServer锁的基础问题探究

    SqlServer需要在执行操作前对目标资源获取所有权,那么久发生锁定,是一个逻辑概念.为了保证事务的ACID特性设计的一种机制. 在多用户并发操作数据时,为了出现不一致的数据,锁定是必须的机制.使用 ...

  2. 有道词典Linux版下载安装

    http://cidian.youdao.com/index-linux.html Ubuntu http://codown.youdao.com/cidian/linux/youdao-dict_1 ...

  3. Hadoop集群最迅速的配置免密码登陆方法

    1:多台机器互相免密登陆的思路(默认你的linux操作系统已经安装好ssh): 第一步:在各自的机器上面生成密钥: 在第1台机器上生产一对钥匙: ssh-keygen -t rsa 在第2台机器上生产 ...

  4. [转] js中的事件委托或是事件代理详解

    起因: 1.这是前端面试的经典题型,要去找工作的小伙伴看看还是有帮助的: 2.其实我一直都没弄明白,写这个一是为了备忘,二是给其他的知其然不知其所以然的小伙伴们以参考: 概述: 那什么叫事件委托呢?它 ...

  5. [转] node.js下mongoose简单操作实例

    Mongoose API : http://mongoosejs.com/docs/api.html // mongoose 链接 var mongoose = require('mongoose') ...

  6. [转] 组件库按需加载 借助babel-plugin-import实现

    前段时间一直在基于webpack进行前端资源包的瘦身.在项目中基于路由进行代码分离,http://www.cnblogs.com/legu/p/7251562.html.对于公司内部的组件库,所有内容 ...

  7. CDOJ 1964 命运石之门【最短路径Dijkstra/BFS】

    给定数字n,m(1<=n,m<=500000) 将n变为n*2花费2,将n变为n-3花费3,要求过程中所有数字都在[1,500000]区间内. 求将n变为m的最少花费 思路:建图 将每个数 ...

  8. Java基础知识➣多线程编程(五)

    概述 Java 给多线程编程提供了内置的支持.一个多线程程序包含两个或多个能并发运行的部分.程序的每一部分都称作一个线程,并且每个线程定义了一个独立的执行路径.使用多线程也是为了充分的利用服务器资源, ...

  9. [HNOI2007]梦幻岛宝珠

    题解: 一道比较好的题目 首先比较显然的就是我们要按照a*2^b的b的顺序来枚举 那么状态f[i][j]表示当前在b,用了a*2^b 刚开始没想到怎么不同层之间搞 看了题解发现非常简单 由于每一层到最 ...

  10. HTML5漫谈(7)——如何保护HTML5应用代码

    独家供稿:移动Labs HTML5应用采用的仍然是Javascript(JS).HTML.CSS 等Web语言,因而其代码保护就是这些Web代码的保护,而HTML5应用主要功能一般采用JS实现,因此J ...