《Effective Java》(第2版)中第二条中提到:遇到多个构造器参数时要考虑用构建器。在复习static关键字和内部类时回头看了一下,这才明白了为什么要用静态内部类来做处理,这里记录一下。

先看再看一下《Effective Java》书中的例子,例子中是用一个类表示包装食品外面显示的营养成分标签。这些标签中有几个是必需的:每份的含量、每罐的含量以及每份的卡路里,还有超过20个可选域:总脂肪量、饱和脂肪量、转化脂肪、胆固醇、钠等。如果用一般的处理方式,直接把这些参数在构造器中初始化的话,有两个缺点:
1、没法体现营养成分的必需和非必需属性
2、参数太多,这样在实例化传参数的时候其实比较难区分的。因为他们几乎都是int型变量,而且即使传递错了也不会有任何提醒。
基于上面的问题,书中转而使用Builder模式,当然,Builder模式能解决上面的问题,那么也间接说明了Builder模式的优点。(1、区分必传和选传参数2、比较明确的表示出参数的含义)
这里直接把书中代码搬过来:
 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{
private final int servingSize;//份容量
private final int servings;//份
//必要参数
public Builder(int servingSize,int servings){
this.servingSize=servingSize;
this.servings=servings;
}
private int calories = ;
private int fat = ;
private int sodium = ;
private int carbohydrate = ;
public Builder calories(int val){
calories = val;
return this;
}
public Builder fat(int val){
fat = val;
return this;
}
public Builder sodium(int val){
sodium = val;
return this;
}
public Builder carbohydrate(int val){
carbohydrate = 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;
}
}
使用时比较简单,而且比较清晰:
 NutritionFacts cocoCola = new NutritionFacts.Builder(,).calories().carbohydrate().build();
注意点:
1、对于NutritionFacts来说,包含了三部分,final成员变量,私有构造器、静态内部类。final成员变量保证了初始化安全性,即在构造器执行完成之前必须显示对成员变量初始化。这里是在构造函数中传入Builder来对其初始化。
2、构造器为什么要声明为私有的?保证了外部创建实例时只能通过静态内部类的build()方法来实现。
3、为什么是静态内部类?因为构造器是私有的,导致外部只能通过内部类的build()方法来实现。而非静态内部类对象的创建又依赖于外部类对象,即必须有外部类对象来创建(外部类对象.new InnerClassName()),这样就陷入了死循环。而静态内部类不需要依赖于外部类对象,只需要通过 “new OutClassName.InnerClassName()”就可以完成实例化。
4、内部类Builder通过final关键字来区分必需参数和非必需参数。通过builder()方法完成外部类实例化。这里利用内部类可以访问外部私有元素的特性。
5、总的来看,就是外部类通过静态内部类完成了自己成员变量的初始化。
 参考书籍:
《Effective Java》

Builder模式的思考(Effective Java)的更多相关文章

  1. Java设计模式(3)建造者模式(Builder模式)

    Builder模式定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. Builder模式是一步一步创建一个复杂的对象,它允许用户可以只通过指定复杂对象的类型和内容就可以构 ...

  2. Builder模式详解及其在Android开发中的应用

    一.引言 在Android开发中,采用Builder模式的代码随处可见,比如说Android系统对话框AlertDialog的使用或者是Android中的通知栏(Notification)的使用,又比 ...

  3. Builder模式的目的是解耦构建过程,为什么要用内部类?

    还没有看过Builder模式的作用,看过一篇介绍Builder模式的文章,这里是关于Builder模式的思考:思考是否有比新建一个内部类更好的方法,首先想到的是 package xyz.n490808 ...

  4. 同事写了一个疯狂的类构造器,我要疯了,Builder 模式都不会么?!

    疯狂的类构造器 最近栈长在做 Code Review 时,发现一段创建对象的方法: Task task = new Task(112, "紧急任务", "处理一下这个任务 ...

  5. 疯狂的类构造器Builder模式,链式调用

    疯狂的类构造器 最近栈长在做 Code Review 时,发现一段创建对象的方法: Task task = new Task(112, "紧急任务", "处理一下这个任务 ...

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

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

  7. effective java 3th item2:考虑 builder 模式,当构造器参数过多的时候

    yiaz 读书笔记,翻译于 effective java 3th 英文版,可能有些地方有错误.欢迎指正. 静态工厂方法和构造器都有一个限制:当有许多参数的时候,它们不能很好的扩展. 比如试想下如下场景 ...

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

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

  9. Builder模式在Java中的应用

    在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成.那么,在实际的开发过程中,我们哪些地方适合用到Builder模式呢?其中使用Build ...

随机推荐

  1. python使用装饰器@函数式化django开发

    django是一个python web开发的框架.作为一个框架MVC的架构已经实现起来了.但是编码的时候你经常要进行进一步的抽象. AOP是一种称为面向切面的开发思想,意思是将部分功能代码在运行时动态 ...

  2. PHP Server Nginx 安装

    1. PHP 安装: http://jingyan.baidu.com/article/b2c186c8f16d05c46ef6ff3c.html PHP 问题: http://www.cnblogs ...

  3. leetcode 697. Degree of an Array

    题目: Given a non-empty array of non-negative integers nums, the degree of this array is defined as th ...

  4. multiprocessing模块

    multiprocessing模块 由于GIL的存在,python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大部分情况需要使用多进程. multiproce ...

  5. 80端口被系统服务【kernel&System】占用解决方案

    netstat -ano | findstr port    //查看端口占用情况 tasklist | findstr port   //查看端口被占用的具体服务名 运行net stop http ...

  6. Java项目打包方式分析

    [TOC] 概述 在项目实践过程中,有个需求需要做一个引擎能执行指定jar包的指定main方法. 起初我们以一个简单的spring-boot项目进行测试,使用spring-boot-maven-plu ...

  7. bootstrap折叠调用collapse()后data-parent不生效问题

    今天做的项目,用到了bootstrap的折叠功能,这个功能需要只展开一个折叠框,点击一个就会自动隐藏另一个,初始按照API做了一下,发现一切运行正常,但是测试的同事提了一个bug,说切换到其他模块后再 ...

  8. C++ primer第五版随笔--2015年1月6日

    记录自己看这本书时的一些内容. 一.引用(reference) 引用为对象起了另外一个名字.例如: int ival=1024: int &relVal1=ival;//对,注意尽量不要用这方 ...

  9. JavaScript基础一(js基础函数与运算符)

    [使用js的三种方式] 1.在HTML标签中,直接内嵌js(并不提倡使用) <button onclick=" alert('点就点')"> 点我啊</butto ...

  10. jquery getScript动态加载JS方法改进详解[转载]

    转载自http://www.jb51.net/article/31973.htm 有许多朋友需要使用getScript方法动态加载JS,本文将详细介绍此功能的实现方法     $.getScript( ...