Effective Java笔记:遇到多个构造器参数时要考虑使用构建器

阻抗匹配与史密斯(Smith)圆图 在找到点B和B'后,我们就能够测量A'到B和B'到D的弧长,前者就是C的归一化电纳值,后者为L的归一化电抗值。当然,表面上看新的点好像是一个不同的阻抗,实际上Z和1/Y表示的是同一个元件(这个新值在圆图上呈现为一个不同的点,而且反射系数也不相同,依次类推)。出现这种情况的原因是我们的图形本身是一个阻抗图,而新的点代表的是一个导纳。这个方程是在复平面(Γr, Γi)上、圆的参数方程(x - a)² + (y - b)² = R²,它以[r/(r + 1), 0]为圆心,半径为1/(1 + r)。 阅读详情

Effective Java笔记:遇到多个构造器参数时要考虑使用构建器

在《Effective Java》的Item 2:遇到多个构造器参数时要考虑使用构建器(Builder 模式)中,当多个可选参数或复杂对象的构造过程导致构造器变得笨拙和难以管理时,使用Builder 模式来替代传统的构造器或静态工厂方法。


问题背景

1. 传统构造器参数增多的问题:

传统的构造器和静态工厂方法在处理多个参数时,会引发一些问题,包括但不限于:

  • 可选参数:有些参数是必需的,有些是可选的。当参数增多时,构造器可能显得难懂。
  • 重载歧义:当有多个重载构造器时,可能很难判断每个构造器的作用。
  • 灵活性不足:某些情况下,部分参数暂时可能是未知或不适用,直接通过构造器设置这些参数时很麻烦。

2. 示例:使用多参数构造器的问题

假设我们设计一个用来表示食品配置信息的类 NutritionFacts,具有以下属性:

  • Serving size(每份大小,必填)
  • Servings(总份数,必填)
  • Calories(热量,可选)
  • Fat(脂肪含量,可选)
  • Sodium(钠含量,可选)
  • Carbohydrate(碳水化合物含量,可选)
- 传统多参数构造器的问题案例:
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 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;
    }
}

// 使用方式
NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27);
问题:
  1. 参数管理困难:调用者必须传递所有参数,即便某些字段是默认值或无关紧要的,也必须传入。
    • 比如,100 是 calorie,0 是 fat,但这两个值的位置很难看出来。
  2. 可读性差:从代码中,很难马上区分每个参数的含义(特别是当某些数字值重复时,容易搞错)。
  3. 扩展性差:新增参数时需要引入新的构造器或修改现有构造器,导致构造器数量爆炸。

解决方案:使用 Builder 模式

Builder 模式 是一个专门用于弥补多参数构造器弊端的设计模式。通过引入一个 “构建器类(Builder)”,可以灵活地构造复杂对象,同时具有更好的可读性和易用性。


Builder 模式的实现

1. 基本实现

以下是将上述 NutritionFacts 类改用 Builder 模式的实现:

public class NutritionFacts {
    // 所有字段仍然是 final 类型
    private final int servingSize;   // 必填
    private final int servings;      // 必填
    private final int calories;      // 可选
    private final int fat;           // 可选
    private final int sodium;        // 可选
    private final int carbohydrate;  // 可选

    // 构造器只接受 Builder
    private NutritionFacts(Builder builder) {
        this.servingSize = builder.servingSize;
        this.servings = builder.servings;
        this.calories = builder.calories;
        this.fat = builder.fat;
        this.sodium = builder.sodium;
        this.carbohydrate = builder.carbohydrate;
    }

    // Builder 静态内部类
    public static class Builder {
        // 必需参数
        private final int servingSize;
        private final int servings;

        // 可选参数,初始化为默认值
        private int calories = 0;
        private int fat = 0;
        private int sodium = 0;
        private int carbohydrate = 0;

        // 构造 Builder,传入必填参数
        public Builder(int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings = servings;
        }

        // 设置可选参数,返回 Builder 本身(链式调用)
        public Builder calories(int calories) {
            this.calories = calories;
            return this;
        }

        public Builder fat(int fat) {
            this.fat = fat;
            return this;
        }

        public Builder sodium(int sodium) {
            this.sodium = sodium;
            return this;
        }

        public Builder carbohydrate(int carbohydrate) {
            this.carbohydrate = carbohydrate;
            return this;
        }

        // 返回最终构建的 NutritionFacts 实例
        public NutritionFacts build() {
            return new NutritionFacts(this);
        }
    }
}
2. 使用 Builder 模式创建对象:
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8) // 必填参数
        .calories(100)
        .sodium(35)
        .carbohydrate(27)
        .build();  // 调用 build() 创建最终对象

优点:

  • 链式调用:灵活选择参数的传递顺序,代码更简洁,且更符合直觉。
  • 可读性高:看到 .calories(100) 就知道这是指热量,.sodium(35) 就知道是钠含量。
  • 扩展性强:可以轻松在 Builder 添加新参数,而无需修改已有代码逻辑。

Builder 模式的优点

  1. 灵活的参数组合:

    • 不再需要为每种参数组合创建多个重载构造器。
    • 必选参数和可选参数分离,必选参数通过 Builder 构造器传递,可选参数通过方法链设置。
  2. 代码可读性、可维护性更高:

    • 参数有明确的上下文意义,使用 .calories()、.fat() 等方法明显高于构造器的参数位置。
  3. 线程安全:

    • 如果 Builder 不暴露到多线程环境,只在单线程中构建对象,那么构建过程是线程安全的。
  4. 易扩展:

    • 添加新参数而无需破坏原有 API 和调用方式,维持向后兼容。例如新增 protein 参数时,仅需在 Builder 增加一个 protein() 方法和相关字段,已有类不受影响。

实际应用中的场景和案例

Builder 模式被广泛应用于以下场景:

  1. 具有多个可选参数的类:

    • 示例:HTTP 请求类(如请求方法、头信息、参数等可选)。
    • 例:HttpRequest.Builder 在 Java 的 HttpClient 中体现了这种模式。
  2. 复杂的对象构造:

    • 适合复杂对象的分步骤构造(如 SQL 查询、配置类)。
    • 例:StringBuilder 的链式调用其实是一种简化版的 Builder 模式。
  3. 不可变对象:

    • 使用 Builder 模式实现的类通常是不可变的,对象一旦构建完成,其状态就无法更改。
    • 例:java.time 中的 LocalDate, LocalTime。

扩展:如果参数非常多怎么办?

  • 分组构建器:
    如果参数很多,可以分组创建多个 Builder。
    比如,Car 可分为 EngineBuilder 和 InteriorBuilder,分别负责引擎和内饰的设置。
Car car = new Car.Builder(new EngineBuilder("V8").horsepower(400).build())
                .interior(new InteriorBuilder("Leather").color("Black").build())
                .build();
优化dalsa相机检测界面 上节实现了使用qt结合dalsa相机显示检测到缺陷的画面,由于窗口过于简陋,本节将进行一个界面优化。 阅读详情

相关推荐

保姆级教程:用GlobleLand30数据+GTB3.3软件,一步步搞定MSPA景观格局分析

本文提供GlobleLand30数据结合GTB3.3软件进行MSPA景观格局分析的保姆级教程,涵盖数据预处理、软件操作、结果解读全流程,特别针对零基础用户常见问题提供解决方案,助力研究者高效完成景观生态学分析。

weixin_26757925的博客 450

第2条 遇到多个构造器参数时考虑用构建器(Build)

第2条 遇到多个构造器参数时考虑用构建器(Build) 适用 构造器/静态工厂具有很多个参数 优势 可以有多个可变参数 灵活,可以单个builder构建多个对象 设置了参数的builder生成了一个很好的抽象工厂 缺点 创建构造器有开销 冗长 替代方案 重叠构造器 多参数情形代码难编写,可读性差 JavaBeans模式 构造过程分离 需额外考虑线程安全 手动freeze比较笨拙 ...

狗天大 133

西门子S7-1200与S7-200SMART的PROFINET通讯实战:从GSD文件生成到数据监控

本文详细解析了西门子S7-1200与S7-200SMART之间实现PROFINET通讯的完整实战流程。核心内容包括将S7-200SMART配置为智能IO设备、生成并安装GSD文件、在TIA Portal中进行网络组态与地址映射,最终实现双向数据交换与监控。该方案为整合新旧设备、构建灵活高效的工业自动化系统提供了可靠路径。

weixin_29271263的博客 245

Java:Effective java学习笔记之 遇到多个构造器参数时要考虑用构建器

Java 遇到多个构造器参数时要考虑用构建器构建器参考 构建器 参考 1、《Effective Java》第2条:遇到多个构造器参数时要考虑用构建器 2、《Effective java》读书记录-第2条-遇到多个构造器参数时要考虑用构建器 3、【读书笔记】《Effective Java》第二章 第2条:遇到多个构造器参数时要考虑使用Builder ...

JMW1407的博客 570

低功耗设计:rush current

在power gating的设计中引入了一个rush current的概念,它的产生原因是switch cell上电过程相当于电容充电过程,会产生一个短期的大电流,称之为rush current。 1.rush current的危害 1)造成巨大的ir drop 2)导致功能错误 3)一些极端例子中,rush current会引发VDD短期崩溃,造成存储在retention register与mem中的数据失效 4)大电流会还对周围always on模块造成干扰,产生大的压降 2.控制rus

m0_61544122的博客 3071

RK3588部署实战:利用RGA硬件加速单元优化YOLOv5的图像预处理与推理性能

摘要:本文探讨了在Rockchip芯片上使用RGA(Rockchip图形加速器)实现YOLOv5图像预处理的过程。通过对比RGA和OpenCV两种方式处理图像的速度,发现RGA加速效果不明显且不稳定(13-17fps),分析原因可能是图片尺寸过小和内存操作消耗时间。文章详细介绍了RGA版本的resize和letterbox实现代码,包括图像缩放、边缘填充等功能,并提供了预处理流程和性能监控方法。结果表明在当前场景下RGA尚未达到预期加速效果,可能与官方代码下架和实现细节有关。

know_F0727的博客 292

读书笔记之《effective java》---遇到多个构造器参数时要考虑用构建器

静态工厂和构造器共同的局限性:不能很好地扩展到大量的可选参数。 例子:包装食品类(必需:每份的含量,每罐的含量及每份的卡路里;还有超过20个可选域:总脂肪量,饱和脂肪量,转化脂肪,胆固醇,钠等微量元素) 一、重叠构造器 这种用法在重构中也有用到,类似的思想。 @Data public class NutritionFacts { private int servingSize;/...

黑呆呆 237

C#量化交易的市场数据采集与分析:从0到1构建你的‘数据雷达’——对比5大神器,代码实战全解析!

数据是量化交易的‘氧气’,而好的数据采集与分析是你的‘呼吸机’!本文5大神器+代码实战,总有一款适合你!(本文代码均经过测试,但请根据实际需求调整!

java专栏 728

Effective Java笔记(2)遇到多个构造器参数时要考虑使用构建器

幸运的是,还有第三种替代方法,它既能保证像重叠构造器模式那样的安全性,也能保证像 JavaB eans 模式那么好的可读性。如果一开始就使用构造器或者静态工厂,等到类需要多个参数时才添加构造器,就会无法控制,那些过时的构造器或者静态工厂显得十分不协调。程序员一向习惯采用重叠构造器( telescoping cons tructor )模式,在这种模式下,提供的第一个构造器只有必要的参数,第二个构造器有一个可选参数,第三个构造器有两个可选参数,依此类推,最后一个构造器包含所有可选的参数。

琅琊之榜 232

【笔记】1.1 拉伸力-伸长(延伸)曲线和应力-应变曲线

过了B点后,由于颈缩导致的截面半径迅速减小,导致真应力迅速上升,切线斜率明显提高。假设试样原长为ε,在力的作用下伸长了dε,那么根据应变的定义,瞬时的应变为dε/ε,总的应变为瞬时应变的累计,假设在瞬时的条件下,试样受载荷变化量为 ΔF ,变化的截面积为 ΔA ,而且ΔA→0,那么瞬时的。由于原始的截面积和原始的标距长度为常数,故得到的曲线长相和拉伸力-伸长(延伸)曲线没啥区别。因为用的都是原始的截面积和原始的标距长度,故称为公称应力和公称应变。如果拉伸力→应力,伸长长度→应变,就会得到应力-应变曲线。

m0_73676887的博客 5269

matlab 质心重合法实现点云配准【2026最新版】

质心重合法是将源点云和目标点云的质心重合,以此缩小两点云集之间的平移误差,从而为下一步粗配准提供更好的初始位置姿态。

点云侠的博客 509

Effective Java学习笔记--遇到多个构造器参数时要考虑使用构建器(Builder)

构造器模式的本质是在目标类中设置一个静态成员变量(Builder),将目标类的各种属性先在这个静态成员变量中设置好,然后通过这个Builder的build方法去构建目标类的对象。这个方式第一允许了目标类属性使用final标识,解决了不可变类的问题;第二属性的设置方法模拟了静态工厂方法的具名特性,使得更易阅读和使用。

weixin_50353846的博客 611

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Effective-Java学习笔记 遇到多个构造器参数时要考虑用构建器

要求创建一个实例,包含多个必选的参数和多个可选参数方法一习惯采用重叠构造器模式,即提供多个参数不同的构造方法,然后根据需要选择相应的构造方法创建实例。但是当有许多参数的时候,代码就很难编写,并难以阅读 方法二JavaBeans模式,用一个无参构造器来创建对象,然后调用setter方法来设置每一个必要的参数,及可选参数。这样产生的代码读起来很容易,但是本身有着严重的缺点:**在构造过程中JavaBea

leijone的博客 1266

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Effective Java 读书笔记:(2) 遇到多个构造器参数时要考虑使用构建器

遇到多个构造器参数时要考虑使用构建器 静态工厂和构造器都有个局限性,它们都不能很好地扩展到大量的可选参数. 问题 当一个类中的参数数量变得很多时,如何方便且灵活地创建含有不同参数的实例成了一个复杂的问题. 解决方案 1.普通方法 重叠构造器模式(telescoping constructor),在这种模式下,提供的第一个构造器只包含必要的参数,第二个构造器包含一个可选参数,第三个构造器包含两个...

WALL.E 289

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

Effective Java读书笔记之遇到多个构造器参数时考虑用构建器(builder)

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

EvanSung的博客 255

【Effective Java笔记】第2条:遇到多个构造器参数时要考虑用构建器(Builder模式)

Effective Java第二条讲构建器(Builder模式)在成员变量比较多的时候相对于构造器和静态工厂、以及JavaBean模式的一些优势 一、创建对象的三种方法 静态工厂和构造器模式 JavaBean模式 构建器(Builder模式) 如题目所说,当遇到多个构造器参数时,考虑用构建器(Builder模式),先说说另外两者在遇到多个参数是的缺点 二、静态工...

浅然的专栏 553

Effective Java笔记第一章创建和销毁对象第二节遇到多个构造器参数时要考虑用构建器

Effective Java笔记第一章创建和销毁对象 第二节:遇到多个构造器参数时要考虑用构建器 1.重叠构造器模式:提供第一个只有必要参数的构造器,第二个构造器有一个可选参数,以此类推,最后一个构造器包含所有的可选参数。 public class Demo1 { private final int a; private final int b; private final int c; private final int d; //两个参数的构造方法 p

zh123456_789的博客 252

effective java 笔记 第2条 遇到多个构造器参数时要考虑用构建器

使用 Builder 模式构造 JavaBean 的好处https://blog.youkuaiyun.com/heiyueya/article/details/56016045https://www.cnblogs.com/ybbzbb/p/5519258.html1. Builder 方式创建的对象,在调用 build() 方法之前是不会创建Request 对象的,所有的属性设置都必须在 build() ...

JavaNotes的博客 304

Effective Java学习笔记之第2条 遇到多个构造器参数时考虑用构建器

第2条 遇到多个构造器参数时要考虑用构建器   静态工厂和构造器有个共同的局限性: 它们都不能很好的扩展到大量的可选参数。   JavaBeans 模式自身有着严重的缺点: 构造过程被分解到了几个调用中,在构造过程中JavaBean可能处于不一致的状态。   JavaBeans模式阻止了把类做成不可变得可能。   Builder模式:不直接生产想要的对象,而是让客户端利用所有必要的参数调用...

weixin_30312557的博客 101

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

类有多个可选参数的解决方案: 1. 重叠构造器模式可行,但是当有许多参数的时候,客户端代码会很难编写,并且仍然较难以阅读。 2. JavaBeans模式,调用一个无参构造器来创造对象,然后调用setter方法来设置每个必要的参数,以及每个相关的可选参数。 缺点:构造过程被分到了几个调用中,在构造过程中JavaBean可能处于不一致的状态。阻止了把类做成不可变的可能,需要程序员确保线程安全。 ...

weixin_30799995的博客 109

读书笔记-《Effective Java》第2条:遇到多个构造器参数时要考虑用构建器

当一个类有很多个属性时,创建对象的时候要么就先创建个对象然后给对象赋值,要么就根据业务需要写很多个构造器, 这样的构造器可读性差。就算用静态工厂也得写很多个,这时候就可以用构建器了。 例如: package org.test; public class People { private String name = ""; private String age = "";...

baitianmingdebai的专栏 203

Effective Java 第二版 学习笔记(2) 创建和销毁对象-多个构造器参数时考虑构建器

参考:Effective Java 第二版 第二章 静态工厂和构造器有个共同的局限,都能很好地扩展到大量的可选参数。 重叠构造器模式可行,但是当有许多参数时,客户端代码会很难编写,并且难以阅读。也可以用JavaBeans莫斯。这种模式中,调用一个无参构造器来创建对象,然后调用setter方法来设置每个必要的参数,以及每个相关的可选参数。但是,JavaBeans莫斯的缺点在于构造过程被分到了...

Dan的专栏 250

《Effective Java》第2条:遇到多个构造器参数时要考虑使用构建器

在《Effective Java》一书中,第2条建议强调了在遇到多个构造器参数时,应考虑使用构建器(Builder)模式。这一建议旨在解决当类的构造器参数过多时,代码可读性和可维护性下降的问题。

探_无止境的博客 958

解读 Java 经典巨著《Effective Java》90条编程法则,第2条:遇到多个构造器参数时要考虑使用构建器

《Effective Java》是由 Joshua Bloch 撰写的经典书籍,提供了 Java 编程中的最佳实践和建议。在书中的第2条建议“遇到多个构造器参数时要考虑使用构建器”,主要是为了处理构造器参数过多时的设计问题。这条建议的主要目的是简化构造器的使用,增加代码的可读性和维护性。

赵士杰——成功并非一蹴而就,而是在持之以恒的努力中逐渐实现。 1532

Effective Java 2 遇到多个构造器参数时要考虑使用构建器

第2个经验法则:用遇到多个构造器参数时要考虑使用构建器(consider a builder when faced with many constructor parameters)上一条讨论了静态工厂相对于构造器来说有五大优势。但静态工厂和构造器有个共同的局限性:它 们都不能很好地扩展到大量的可选参数。对于需要多参数的类,应该用哪种构造器或者静态工厂来编写呢?接下来,我将通过Java代码示例来对比分析构造器模式、JavaBeans模式以及建造者模式在处理多参数情况下的应用。

cangshanjiang的博客 1117

Effective java 学习第二条-遇到多个构造器参数时要考虑使用构建器

本文探讨了处理大量可选参数的三种设计模式:重叠构造器、JavaBeans模式和建造者模式,并分析了各自的优缺点。重叠构造器虽然安全但会导致组合爆炸和可读性问题;JavaBeans模式提高了可读性但牺牲了不可变性和线程安全;而建造者模式完美结合了两者优势,通过链式调用确保对象创建的一致性和可读性,同时支持不可变对象和参数校验,是处理复杂可选参数的最佳实践。

m0_46557728的博客 1079
上一篇: Effective Java笔记:静态工厂方法代替构造器
下一篇: Effective Java笔记:用私有构造器或者枚举类型强化 Singleton 属性
Jooou
博客等级 码龄9年 226粉丝 58原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值