建造者模式Builder——优雅的使用姿势

news2024/11/30 0:13:16

在面向对象设计中,建造者模式(Builder Pattern) 是一种非常经典的设计模式,特别适用于需要构造复杂对象的场景。Lombok 提供的 @Builder 注解极大简化了 Builder 模式的实现,而 toBuilder = true 则进一步增强了它的灵活性,使我们能够基于已有对象快速创建新的变体。

本文将深入探讨 @Builder 背后的设计模式,适用场景、不适用场景,以及 @Builder(toBuilder = true) 的使用方法。


一、Builder 模式简介

Builder 模式 是一种创建型设计模式,主要用于构造具有多个可选参数或复杂结构的对象。其核心思想是通过一个 Builder 类一步步设置对象的属性,最后构造出一个完整的对象。

传统 Builder 模式的实现

以构建一个复杂的 Car 类为例,传统的 Builder 模式如下:

public class Car {
    private final String engine;
    private final int seats;
    private final String color;

    private Car(CarBuilder builder) {
        this.engine = builder.engine;
        this.seats = builder.seats;
        this.color = builder.color;
    }

    public static class CarBuilder {
        private String engine;
        private int seats;
        private String color;

        public CarBuilder engine(String engine) {
            this.engine = engine;
            return this;
        }

        public CarBuilder seats(int seats) {
            this.seats = seats;
            return this;
        }

        public CarBuilder color(String color) {
            this.color = color;
            return this;
        }

        public Car build() {
            return new Car(this);
        }
    }
}

使用方式:

Car car = new Car.CarBuilder()
                 .engine("V8")
                 .seats(4)
                 .color("Red")
                 .build();

虽然功能强大,但手动编写 Builder 模式的代码往往繁琐冗长。Lombok 的 @Builder 注解可以让我们完全摆脱这一繁琐过程。


二、Lombok 的 @Builder 简化实现

Lombok 的 @Builder 注解会自动为目标类生成一个静态内部类,作为 Builder 类,同时提供链式方法和 build() 方法。

基本用法

import lombok.Builder;
import lombok.ToString;

@Builder
@ToString
public class Car {
    private final String engine;
    private final int seats;
    private final String color;
}

public class Main {
    public static void main(String[] args) {
        Car car = Car.builder()
                     .engine("V8")
                     .seats(4)
                     .color("Red")
                     .build();

        System.out.println(car);
    }
}

输出:

Car(engine=V8, seats=4, color=Red)

可以看到,@Builder 自动生成了 CarBuilder 类,并支持链式调用,大幅简化了代码。


三、@Builder(toBuilder = true) 的增强功能

@Builder 配置了 toBuilder = true 时,Lombok 会为目标类生成一个 toBuilder() 方法,允许基于已有对象创建一个新的 Builder。这种增强功能特别适用于需要对不可变对象进行部分修改的场景。

示例代码

@Builder(toBuilder = true)
@ToString
public class Car {
    private final String engine;
    private final int seats;
    private final String color;
}

public class Main {
    public static void main(String[] args) {
        // 创建初始对象
        Car car = Car.builder()
                     .engine("V8")
                     .seats(4)
                     .color("Red")
                     .build();

        // 基于现有对象修改部分字段
        Car updatedCar = car.toBuilder()
                            .color("Blue")
                            .build();

        System.out.println("Original Car: " + car);
        System.out.println("Updated Car: " + updatedCar);
    }
}

输出:

Original Car: Car(engine=V8, seats=4, color=Red)
Updated Car: Car(engine=V8, seats=4, color=Blue)

toBuilder() 方法的作用:

  • 返回一个 Builder 对象,其中的属性初始值为当前对象的值。
  • 可以灵活修改部分属性值,构造新的对象。

四、Builder 模式的适用场景

1. 需要构造复杂对象时

当一个类的构造方法包含多个参数,特别是可选参数时,使用 Builder 模式可以避免构造器参数混乱问题。

例如,构造一个具有多个可选属性的 Car 类:

Car car = Car.builder()
             .engine("V8")
             .seats(4)
             .color("Red")
             .build();

2. 需要不可变对象时

Builder 模式是构造不可变对象的最佳选择。通过 final 修饰属性和 @Builder,可以确保对象一旦创建,所有字段值都不可更改。

3. 需要对象的灵活更新时

配合 toBuilder = true,可以在保持不可变特性的同时灵活更新对象。例如:

Car updatedCar = car.toBuilder()
                    .seats(5)
                    .build();

这种场景常见于配置类、请求对象、数据模型等需要频繁修改但又需要保持线程安全的地方。


五、Builder 模式的不适用场景

尽管 Builder 模式功能强大,但它并不适合所有情况:

1. 简单对象的构造

对于只有少量字段的类,使用 Builder 反而显得繁琐。例如:

class User {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

对于这样的简单对象,直接使用构造方法更简洁高效。

2. 对象生命周期短,频繁创建

在高性能场景中,如果对象生命周期非常短,且需要频繁创建,Builder 的链式调用可能带来额外开销。

3. 过度设计的风险

如果类的复杂性并不需要 Builder 模式,但仍然引入 Builder,则可能导致代码的复杂性增加。例如,对某些工具类、纯数据类使用 Builder 可能是过度设计。


六、总结

1. @Builder 与设计模式

  • Builder 模式非常适合构造复杂对象或不可变对象。
  • Lombok 的 @Builder 大幅简化了 Builder 模式的实现,让开发者专注于业务逻辑。

2. toBuilder = true 的增强

  • 提供了灵活性,允许基于现有对象创建新的变体。
  • 在不可变对象的更新场景中尤为实用。

3. 适用与不适用场景

  • 适用场景:复杂对象构造、不可变对象、多参数类。
  • 不适用场景:简单类、高性能频繁创建对象场景、过度设计。

4. 推荐实践

  • 对于复杂业务实体或配置类,使用 @BuildertoBuilder = true 是最佳实践。
  • 对于简单类或数据模型,直接使用构造方法或工厂方法即可。

通过合理地选择和应用 Builder 模式,可以有效提升代码的可读性、可维护性以及灵活性。善用 Lombok 的 @Builder,可以让你的代码更加优雅高效!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2250089.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

视频汇聚平台Liveweb国标GB28181视频平台监控中心设计

在现代安防视频监控领域,Liveweb视频汇聚平台以其卓越的兼容性和灵活的拓展能力,为用户提供了一套全面的解决方案。该平台不仅能够实现视频的远程监控、录像、存储与回放等基础功能,还涵盖了视频转码、视频快照、告警、云台控制、语音对讲以及…

hubu新星杯实践能力赛模拟赛web/Misc-wp

ez_eval <?php highlight_file(__FILE__); error_reporting(0);$hubu $_GET[hubu];eval($hubu);?> 先进行代码审计&#xff0c;GET传参hubu&#xff0c;并执行命令&#xff0c;没有任何绕过&#xff0c;放开手脚去做 payload: ?hubusystem(cat /f*); #直接rcerc…

【前端】跨域问题与缓存

报错如下&#xff1a; 原因&#xff1a; 浏览器 缓存跨域&#xff0c;顾名思义是由于浏览器的缓存机制导致的一种跨域情况。这种跨域一般会出现在浏览器通过一些无视跨域的标签和css(如img、background-image)缓存了一些图片资源之后&#xff0c;当再次发起图片请求时&#xff…

抓包之OSI七层模型以及TCPIP四层模型

写在前面 本文看下OSI七层模型以及TCP/IP四层网络模型&#xff0c;并尝试使用wireshark进行验证。 1&#xff1a;OSI七层网络模型和TCP/IP四层模型 全称&#xff1a;open system interconnection。 需要注意OSI七层模型最终是没有落地的&#xff0c;最终落地的是与之类似的…

#渗透测试#红蓝攻防#HW#漏洞挖掘#漏洞复现02-永恒之蓝漏洞

免责声明 本教程仅为合法的教学目的而准备&#xff0c;严禁用于任何形式的违法犯罪活动及其他商业行为&#xff0c;在使用本教程前&#xff0c;您应确保该行为符合当地的法律法规&#xff0c;继续阅读即表示您需自行承担所有操作的后果&#xff0c;如有异议&#xff0c;请立即停…

MTK 展锐 高通 sensorhub架构

一、MTK平台 MTK框架可以分为两部分&#xff0c;AP和SCP。 AP是主芯片&#xff0c;SCP是协处理器&#xff0c;他们一起工作来处理sensor数据。 SCP 是用来处理sensor和audio相关功能和其他客制化需求的一个协处理理器&#xff0c;MTK SCP选择freeRTOS作为操作系统&#xff0c…

视觉语言模型(VLM)学习笔记

目录 应用场景举例 VLM 的总体架构包括&#xff1a; 深度解析&#xff1a;图像编码器的实现 图像编码器&#xff1a;视觉 Transformer 注意力机制 视觉-语言投影器 综合实现 训练及注意事项 总结 应用场景举例 基于文本的图像生成或编辑&#xff1a;你输入 “生成一张…

[AutoSar]BSW_Diagnostic_007 BootLoader 跳转及APP OR boot response 实现

目录 关键词平台说明背景一、Process Jump to Bootloader二、相关函数和配置2.1 Dcm_GetProgConditions()2.2 Dcm_SetProgConditions() 三、如何实现在APP 还是BOOT 中对10 02服务响应3.1 配置3.2 code 四、报文五、小结 关键词 嵌入式、C语言、autosar、OS、BSW、UDS、diagno…

如何启用本机GPU硬件加速猿大师播放器网页同时播放多路RTSP H.265 1080P高清摄像头RTSP视频流?

目前市面上主流播放RTSP视频流的方式是用服务器转码方案&#xff0c;这种方案的好处是兼容性更强&#xff0c;可以用于不同的平台&#xff0c;比如&#xff1a;Windows、Linux或者手机端&#xff0c;但是缺点也很明显&#xff1a;延迟高、播放高清或者同时播放多路视频视频容易…

设置ip和代理DNS的WindowsBat脚本怎么写?

今天分享一个我们在工作时&#xff0c;常见的在Windows中通过批处理脚本&#xff08;.bat 文件&#xff09;来设置IP地址、代理以及DNS 相关配置的示例&#xff0c;大家可以根据实际需求进行修改调整。 一、设置静态IP地址脚本示例 以下脚本用于设置本地连接&#xff08;你可…

深度学习-49-AI应用实战之基于HyperLPR的车牌识别

文章目录 1 车牌识别系统1.1 识别原理1.1.1 车牌定位1.1.2 字符识别2 实例应用2.1 安装hyperlpr32.2 识别结果2.3 可视化显示2.4 结合streamlit3 附录3.1 PIL.Image转换成OpenCV格式3.2 OpenCV转换成PIL.Image格式3.3 st.image嵌入图像内容3.4 参考附录1 车牌识别系统 车牌识别…

基于深度学习的手势识别算法

基于深度学习的手势识别算法 概述算法原理核心逻辑效果演示使用方式参考文献 概述 本文基于论文 [Simple Baselines for Human Pose Estimation and Tracking[1]](ECCV 2018 Open Access Repository (thecvf.com)) 实现手部姿态估计。 手部姿态估计是从图像或视频帧集中找到手…

【Linux】-操作系统

&#x1f511;&#x1f511;博客主页&#xff1a;阿客不是客 &#x1f353;&#x1f353;系列专栏&#xff1a;深入代码世界&#xff0c;了解掌握 Linux 欢迎来到泊舟小课堂 &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞⭐收藏➕关注 ​​ 一、冯•诺依曼架构&#xff…

2024最新python使用yt-dlp

2024最新python使用yt-dlp下载YT视频 1.获取yt的cookie1&#xff09;google浏览器下载Get cookies.txt LOCALLY插件2&#xff09;导出cookie 2.yt-dlp下载[yt-dlp的GitHub地址](https://github.com/yt-dlp/yt-dlp?tabreadme-ov-file)1&#xff09;使用Pycharm(2024.3)进行代码…

Mybatis集成篇(一)

Spring 框架集成Mybatis 目前主流Spring框架体系中&#xff0c;可以集成很多第三方框架&#xff0c;方便开发者利用Spring框架机制使用第三方框架的功能。就例如本篇Spring集成Mybatis 简单集成案例&#xff1a; Config配置&#xff1a; Configuration MapperScan(basePack…

C51相关实验

C51相关实验 LED (P2 / 0~7)蜂鸣器 (P2^5)数码管 (P0 0~7 段 &#xff0c;P2 2~4 位)独立按键 &#xff08;P3^1 P3^0 P3^2 P3^3&#xff09;直流电机 (J47 5v 01~04)综合实验矩阵按键 (P1组 0~7)LED点阵 LED (P2 / 0~7) //功能&#xff1a;1.让开发板的LED全亮&#xff0c;2,…

C++语法·叭

阁下何不乘风起&#xff0c;扶摇直上九万里。 qi fei 目录 内存管理 分区介绍 1.栈区&#xff1a; 2.内存映射段&#xff1a; 3.堆&#xff1a; 4.数据段&#xff1a; 5.代码段&#xff1a; 补充&#xff1a; C内存管理&#xff08;简略回忆&#xff09; C内存…

数据库期末复习题库

1. Mysql日志功能有哪些? 记录日常操作和错误信息&#xff0c;以便了解Mysql数据库的运行情况&#xff0c;日常操作&#xff0c;错误信息和进行相关的优化。 2. 数据库有哪些备份方法 完全备份&#xff1a;全部都备份一遍表备份&#xff1a;只提取数据库中的数据&#xff0…

矩阵重新排列——rot90函数

通过 r o t 90 rot90 rot90函数可以将矩阵进行旋转 用法&#xff1a; r o t 90 ( a , k ) rot90(a,k) rot90(a,k)将矩阵 a a a按逆时针方向旋转 k 9 0 ∘ k\times90^\circ k90∘

挑战用React封装100个组件【001】

项目地址 https://github.com/hismeyy/react-component-100 组件描述 组件适用于需要展示图文信息的场景&#xff0c;比如产品介绍、用户卡片或任何带有标题、描述和可选图片的内容展示 样式展示 代码展示 InfoCard.tsx import ./InfoCard.cssinterface InfoCardProps {ti…