问题,面对这种一个构造器具备多个参数的问题,现有的做法是使用重叠构造器的方式,该方式存在的问题:

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);
}
}

重叠构造器存在的问题是,客户端使用NutritionFacts类容易出错,也比较困难,困难在于,客户端要记住构造器的每个参数的含义及顺序。这种方式,可读性也差,原因就是,要读懂一句代码,就要记住该构造器所用所有参数的含义。

-------------------------------------------------------------------------------------------------------------------------------------------------------------

一种替代的解决办法:

public class NutritionFacts {
// Parameters initialized to default values (if any)
private int servingSize = -1; // Required; no default value
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的方式,使用空参数的构造器,创建对象;然后,把构造器参数的设置,放到setter方法来实现,如上。
存在的问题,构造过程,被分到了几个调用中。上述代码块,不能被分裂开来执行,如果分裂开执行,会导致创建的对象状态不一致。
 
存在的问题就是,会导致创建的对象,其状态不一致。这在多线程程序中会出现。比如,cocaCola.setSodium(35);在执行这句代码之前,对象cocaCola已经被其它线程使用了,这就会导致使用了不状态不正确的cocaCola对象。
简单地说,就是创建对象,并且设置对象状态的代码,并不原子化。
------------------------------------------------------------------------------------------------------------
另一种解决办法:Builder模式
 
    public static void main(String[] args) {
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8)
.calories(100).sodium(35). carbohydrate(27).build();
}

对比:

重叠构造器方式
 public static void main(String[] args) {
NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27);
}

JavaBean方式

  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);
}
 
Builder模式,客户端在使用的时候,需要记住两个必备参数的含义及顺序;然后,如果需要其它可选构造参数,则通过调用对应的方法来实现。
比如,需要可选参数calories,则调用calories(int val)方法。这个可读性要好,用户通过阅读该方法的名称得知参数的含义,知道此时传递的构造器参数,是用来设定calories的值的。
这就解决了重叠构造器方式存在的问题,可读性差,客户端程序员使用容易出错的问题。
另外,使用Builder模式,创建对象时,代码都是同时执行,而不是分成各个语句,是一条独立的语句,而不是分成多条语句。
 
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();
}
}

  

Item 2---遇到构造器具有多个参数时,要考虑用构建器;Builder模式的更多相关文章

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

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

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

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

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

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

  4. Java 构造器 遇到多个构造器时要考虑用构建器

    静态工厂和构造器有个共同的局限性:它们都不能很好地扩展到大量的可选参数. 当一个类中有若干个必选属性和多个可选属性时,采用重叠构造器模式.JavaBeans模式或者Builder模式,但各有优劣. 当 ...

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

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

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

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

  7. Builder设计模式--改善构造器多个参数时可显著改善可读性

    作为一名程序开发者,设计模式其实一直有在接触,只是没有专门的去学过,所以可能对设计模式没有一个系统的理解.在一次项目中,需要使用到第三方服务商提供的功能,为了尽快的熟悉其功能代码,在官网下了demo来 ...

  8. 【代码优化】当许多构造函数的参数,请考虑使用builder模式

    静态工厂和构造具有共同的局限性:我们不能扩展到大量的非常好的可选参数. 1.对于多个可选參数的构造器.我们都习惯採用重叠构造器模式.比方一个參数的构造器调用2个參数的构造器.     2个參数的构造器 ...

  9. Effective Java 第三版——2. 当构造方法参数过多时使用builder模式

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

随机推荐

  1. c#事件实质

    c#的事件实际上是对windows消息的封装: windows消息系统分为3部分:消息队列,消息循环,窗口过程(wndproc函数)

  2. PAT 甲级 1012 The Best Rank

    https://pintia.cn/problem-sets/994805342720868352/problems/994805502658068480 To evaluate the perfor ...

  3. node.js cmd 输入npm-v无反应

    今天安装node,先是提示node版本太低.去官网更新了一下,然后 npm install -g vue-cli 结果出了个"npm ERR! errno -4048" 百度出 这 ...

  4. 手把手教你写Kafka Streams程序

    本文从以下四个方面手把手教你写Kafka Streams程序: 一. 设置Maven项目 二. 编写第一个Streams应用程序:Pipe 三. 编写第二个Streams应用程序:Line Split ...

  5. Linux服务器记录并查询历史操作记录

    Linux服务器在使用过程中,经常会有除自己之外的其他人员使用.并不是每个人都对Linux服务器特别熟悉,难免会有一些操作导致服务器报错. 因此,监控Linux服务器的操作并记录下来,是非常有必要的! ...

  6. linux解压zip

    用 unzip 的先安装 yum install -y unzip #unzip file.zip -d /root  -d指解压路径 ,不写的话默认当前目录

  7. WPF通过NPIO读写Excel操作

    自已摸索实现了对excel简单的上传和下载并做了一个封装类,下面分享一下. 先去官网:http://npoi.codeplex.com/下载需要引入dll(可以选择.net2.0或者.net4.0的d ...

  8. IBatis Map时间参数文字格式不匹配!

    CS. ht.Add("start_time", startTime); Map <isNotNull prepend="and" property=&q ...

  9. 【刷题】洛谷 P4329 [COCI2006-2007#1] Bond

    题意翻译 有 \(n\) 个人去执行 \(n\) 个任务,每个人执行每个任务有不同的成功率,每个人只能执行一个任务,求所有任务都执行的总的成功率. 输入第一行,一个整数 \(n\) ( \(1\leq ...

  10. 【SPOJ】Highways(矩阵树定理)

    [SPOJ]Highways(矩阵树定理) 题面 Vjudge 洛谷 题解 矩阵树定理模板题 无向图的矩阵树定理: 对于一条边\((u,v)\),给邻接矩阵上\(G[u][v],G[v][u]\)加一 ...