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

ops/2024/11/28 19:07:41/

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

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


一、Builder 模式简介

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

传统 Builder 模式的实现

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

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

使用方式:

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

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


二、Lombok 的 @Builder 简化实现

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

基本用法

java">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。这种增强功能特别适用于需要对不可变对象进行部分修改的场景。

示例代码

java">@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 类:

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

2. 需要不可变对象时

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

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

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

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

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


五、Builder 模式的不适用场景

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

1. 简单对象的构造

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

java">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.ppmy.cn/ops/137444.html

相关文章

二叉树:堆的建立和应用

在建立堆之前,我们要知道什么是树和二叉树 树 树是一种非线性的数据结构,它是由n(n>0)个结点组成的一个具有层次关系的集合,之所以把它叫做树,是因为它长得像一棵倒挂的树,也就是根在上面&…

微信小程序蓝牙writeBLECharacteristicValue写入数据返回成功后,实际硬件内信息查询未存储?

问题:连接蓝牙后,调用小程序writeBLECharacteristicValue,返回传输数据成功,查询硬件响应发现没有存储进去? 解决:一直以为是这个write方法的问题,找了很多相关贴,后续进行硬件日志…

CSS:怎么把网站都变成灰色

当大家看到全站的内容都变成了灰色,包括按钮、图片等等。这时候我们可能会好奇这是怎么做到的呢? 有人会以为所有的内容都统一换了一个 CSS 样式,图片也全换成灰色的了,按钮等样式也统一换成了灰色样式。但你想想这个成本也太高了…

探索开源多模态视频生成模型:CogVideoX1.5-5B

随着人工智能技术的快速发展,多模态学习逐渐成为研究热点之一。多模态学习旨在通过整合不同类型的感知数据(如文本、图像、音频等),以提高机器学习模型的性能和泛化能力。在这一背景下,由智谱AI开发的 CogVideoX1.5-5B…

如何搭建一个小程序:从零开始的详细指南

在当今数字化时代,小程序以其轻便、无需下载安装即可使用的特点,成为了连接用户与服务的重要桥梁。无论是零售、餐饮、教育还是娱乐行业,小程序都展现了巨大的潜力。如果你正考虑搭建一个小程序,本文将为你提供一个从零开始的详细…

c#常见面试题与解析

1.简述 private、 protected、 public、internal 修饰符的访问权限 public 公有的 protected 受保护的 private 私有的 internal 内部的 前三者的关系public>protected>private internal表示在同意程序集内,可访问。 2.列举ASP.NET页面之间传递值的几种…

数据结构(初阶6)---二叉树(遍历——递归的艺术)(详解)

二叉树的遍历与练习 一.二叉树的基本遍历形式1.前序遍历(深度优先遍历)2.中序遍历(深度优先遍历)3.后序遍历(深度优先遍历)4.层序遍历!!(广度优先遍历) 二.二叉树的leetcode小练习1.判断平衡二叉树1)正常解法2)优化解法 2.对称二叉…

索尼欲推新一代PSP/PSV掌机,将支持PS4/5游戏

原文转载修改自(更多互联网新闻/搞机小知识): 新一代索尼掌机将支持PS4/PS5游戏,或与PS6同时期推出 说起索尼掌机,很难逃得过一句:怒其不争。PSP、PSV打下的大好河山,愣是断送在时代洪流的大浪…