【设计模式】builder 创建者设计模式详解(包含电商应用场景及代码示例)

一、builder 简介

在常见的设计模式中,“Builder” 通常是指一种设计模式,而不是具体的类或方法。Builder 模式是一种创建型设计模式,其目的是通过提供一个独立的构建器类来构建一个复杂对象。

建造者模式(Builder Pattern) 是一种创建型设计模式,它的主要目标是为了将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。

1、主要角色

  • 产品(Product):表示被构建的复杂对象。在建造过程完成后,该对象通常包含多个部件。
  • 抽象建造者(Builder):声明了创建产品各个部件的抽象接口。通常包含创建和返回产品的方法。
  • 具体建造者(Concrete Builder):实现了抽象建造者接口,负责实际构建产品的各个部件。具体建造者通常会有一个与产品相关的成员变量,用于保存当前产品的状态。
  • 指导者(Director):负责使用建造者对象构建产品。指导者通常不知道具体产品的类型和内部结构,仅仅负责按照一定的构建步骤调用建造者的方法。

在 Java 中,Builder 模式通常由一个包含所有构建步骤的内部静态类(称为 Builder 类)来实现。这个 Builder 类负责设置对象的各个属性,最后通过一个 build() 方法来构建目标对象。

总体而言,Builder 模式是通过一个独立的构建器类来创建对象,使得对象的构建过程更加灵活和清晰。

二、builder 用法及实现

1、手写builder类

一般来说,builder 的用法如下:

  • 创建一个静态内部类作为建造者(Builder):

        private String property1;private int property2;// 私有构造函数,限制直接实例化private MyClass() {}// Getter 方法省略...// 静态内部类作为建造者public static class Builder {private MyClass instance = new MyClass();public Builder withProperty1(String value) {instance.property1 = value;return this;}public Builder withProperty2(int value) {instance.property2 = value;return this;}public MyClass build() {return instance;}}// 其他静态工厂方法或实例方法...// 示例:使用 builder() 创建对象public static Builder builder() {return new Builder();}} 
    
  • 使用建造者设置属性:

    MyClass myObject = MyClass.builder().withProperty1("value1").withProperty2(42).build(); 
    

通过这种方式,你可以在创建对象的时候逐步设置属性,而不是通过构造函数传递参数。这样的设计使得代码更加清晰,易于维护,尤其当有多个可选属性时,建造者模式可以提供更好的灵活性。

2、Lombok实现

使用 Lombok 这样的工具,它提供了 @Builder 注解,该注解可以用于生成 Builder 模式相关的代码。下面是一个使用 Lombok 的 @Builder 注解的简单示例:详情参考【注解】@Builder、@SuperBuilder Lombok 中的建设者

import lombok.Builder;
import lombok.Getter;@Getter
@Builder
public class Example {private final String name;private final int age;
}
// 在其他类中使用
Example example = Example.builder().name("John").age(25).build();

在这个示例中,Builder 注解帮助生成了一个名为 builder 的静态内部类,该类用于创建 Example 对象的实例。这种方式使得对象的创建更加清晰和方便。

请注意,@Builder 是 Lombok 提供的功能,如果你没有使用 Lombok,你需要手动编写 Builder 模式的代码。

三、作用和优势

1、工作流程

  • 客户端(Client):创建指导者对象,并指定一个具体的建造者对象。
  • 指导者(Director):调用具体建造者的一系列方法,按照一定的步骤来构建产品。
  • 具体建造者(Concrete Builder):实现了具体的构建步骤,负责构建产品的各个部件。
  • 产品(Product):表示最终构建成功的对象。

2、优点

  • 分离构建和表示:建造者模式将对象的构建和最终表示分离,使得相同的构建过程可以创建不同的表示。
  • 更好的控制构建过程:通过指导者来控制构建过程,可以灵活地配置和改变产品的构建流程。
  • 更好的复用性:可以通过不同的具体建造者来创建不同类型的产品,提高了代码的复用性。
  • 更好的扩展性:增加新的具体建造者无需修改指导者的代码,符合开闭原则。

四、应用场景

  • 需要创建复杂对象:当对象的构建过程较为复杂,涉及多个部件组合,且这些部件可能存在多种组合方式时,可以考虑使用建造者模式。
  • 对象的构建步骤顺序不固定:如果对象的构建步骤的顺序不固定,或者某些步骤可以省略,可以通过建造者模式更灵活地构建对象。
  • 想要避免使用过多的构造方法:在类的构造方法中,参数的组合可能有多种情况,如果为每一种情况都提供一个构造方法,会导致构造方法的数量急剧增加。建造者模式可以通过一系列的方法来设置对象的不同部分,避免构造方法的爆炸性增长。
  • 希望在创建对象时能够更好地控制对象的构建过程:通过使用指导者(Director)来封装对象的构建过程,客户端只需要指定具体的建造者和调用指导者的构建方法,而无需关心对象的具体构建过程。
  • 想要避免在客户端暴露产品的内部表示:建造者模式将产品的构建和最终表示分离,客户端只需要关心产品的最终状态而不需要知道具体的构建细节,从而降低了客户端与产品的耦合度。

总的来说,建造者模式适用于需要创建复杂对象,且构建过程灵活多变的场景。在这种模式下,将对象的构建过程封装在具体建造者中,通过指导者来统一调度,使得客户端可以更方便地构建出所需的对象。

五、应用实例(电商)

在电商项目中,一个典型的场景是创建订单(Order)。订单通常包含多个部分,例如订单项、收货地址、支付信息等,而每个部分的构建可能涉及到多个步骤和参数。建造者模式在这种情况下可以很好地应用。

让我们考虑一个简化的订单创建过程,使用建造者模式来构建订单对象。假设订单包括订单号、订单项列表、收货地址、支付信息等。

1、首先,定义订单对象:

// 订单对象
public class Order {private String orderNumber;private List<OrderItem> orderItems;private String shippingAddress;private String paymentInfo;// 构造方法私有化,通过建造者来构建对象private Order() {}// 提供获取订单信息的方法// ...
}

2、然后,定义订单项对象:

// 订单项对象
public class OrderItem {private String productCode;private int quantity;// 构造方法public OrderItem(String productCode, int quantity) {this.productCode = productCode;this.quantity = quantity;}// 提供获取订单项信息的方法// ...
}

3、接下来,定义订单的建造者(OrderBuilder):

// 订单建造者
public class OrderBuilder {private Order order;public OrderBuilder() {this.order = new Order();}public OrderBuilder setOrderNumber(String orderNumber) {order.orderNumber = orderNumber;return this;}public OrderBuilder addOrderItem(String productCode, int quantity) {if (order.orderItems == null) {order.orderItems = new ArrayList<>();}order.orderItems.add(new OrderItem(productCode, quantity));return this;}public OrderBuilder setShippingAddress(String shippingAddress) {order.shippingAddress = shippingAddress;return this;}public OrderBuilder setPaymentInfo(String paymentInfo) {order.paymentInfo = paymentInfo;return this;}public Order build() {return order;}
}

4、最后,在客户端中使用建造者模式来构建订单:

public class Main {public static void main(String[] args) {// 使用建造者构建订单Order order = new OrderBuilder().setOrderNumber("123456").addOrderItem("P001", 2).addOrderItem("P002", 1).setShippingAddress("123 Main St, City").setPaymentInfo("Credit Card").build();// 打印订单信息System.out.println("Order Number: " + order.getOrderNumber());System.out.println("Shipping Address: " + order.getShippingAddress());System.out.println("Payment Info: " + order.getPaymentInfo());System.out.println("Order Items: " + order.getOrderItems());}
}

在这个例子中,通过使用建造者模式,客户端可以按照自己的需求逐步设置订单的各个部分,最后调用 build() 方法生成订单对象。这种方式既灵活又可读性好,而且使得订单对象的创建过程与客户端解耦。

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

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

相关文章

大模型在游戏行业的应用分析

文章目录 一、大模型作用1&#xff09;节省美术成本2&#xff09;模仿用户肖像&#xff0c;精准投放3&#xff09;买量流程的自动化4&#xff09;缩短视频素材制作周期5&#xff09;例如新营销形式宣传&#xff08;图生图&#xff09;5&#xff09;故事设计6&#xff09;辅助代…

figma导入psd实战笔记

最近发现figma特别好用 并且插件生态特别庞大 如 将设计图转成vue react react-native 项目 flutter 项目 最重要的是 可以集成vscode 插件使用 使用蓝湖久了 感觉蓝湖 有写繁琐 同事扩展功能有限 Figma: The Collaborative Interface Design ToolFigma is the leading collabo…

欧拉函数算法总结

知识概览 欧拉函数为1~n中与n互质的数的个数。假设一个数N分解质因数后的结果为 则欧拉函数 这可以用容斥原理来证明。 欧拉函数的应用 欧拉定理&#xff1a;若a与n互质&#xff0c;则。 费马小定理&#xff1a;欧拉定理中的n为质数p时&#xff0c;可以得到若a与p互质&#xff…

深入理解计算机系统(2):信息的表示和处理

信息存储 大多数计算机使用 8 位的块&#xff0c;或者字节(byte)&#xff0c;作为最小的可寻址的内存单位&#xff0c;而不是访问内存中单独的位。机器级程序将内存视为一个非常大的字节数组&#xff0c;称为虚拟内存(virtual memory)。内存的每个字节都由一个唯一的数字来标识…

vcruntime140_1.dll无法继续执行代码怎么办?6个修复方法分享

找不到vcruntime1401.dll”。这个错误提示通常意味着我们的计算机缺少了一个重要的动态链接库文件。本文将介绍vcruntime1401.dll是什么文件、它的作用以及当电脑丢失该文件时可能产生的影响&#xff0c;并提供6个解决方法来解决这个问题。 一、vcruntime1401.dll是什么文件&a…

Linux指令(一)

今天来学习Linux的一些基本的指令。 今天要学习的指令有ls&#xff0c;pwd&#xff0c;mkdir&#xff0c;cd&#xff0c;touch&#xff0c;rm等。 指令的格式 在Linux中&#xff0c;指令的语法通常遵循以下格式&#xff1a; command [options] [arguments] command 是要执行…

便捷特惠的快递寄件快递物流折扣平台 ,通常都有什么常见问题?

首先&#xff0c;最重要的一点是怎么寄快递更便宜&#xff1f; 我们在寄快递时&#xff0c;尽量把包裹压缩空间大一点&#xff0c;这样在体积上面就会减少一部分的费用呢&#xff0c;另外就是选择有优惠的平台下单。例如在闪侠惠递平台下单&#xff0c;单单打折&#xff0c;单…

AC修炼计划(AtCoder Beginner Contest 335)A-F

传送门&#xff1a; AtCoder Beginner Contest 335 (Sponsored by Mynavi) - AtCoder A&#xff0c;B&#xff0c;C&#xff0c;D还算比较基础&#xff0c;没有什么思路&#xff0c;纯暴力就可以过。 这里来总结一下E和F E - Non-Decreasing Colorful Path 最开始以为是树形…

终于学会听英文歌了:Because of You

作词 : Ben Moody/David hodges/Kelly Clarkson 作曲 : Ben Moody/David hodges/Kelly Clarkson I will not make the same mistakes that you did 我不會 重蹈你的覆轍 I will not let myself cause my heart so much misery 我不會 讓我自己心煩憂苦 I will not break the wa…

【C++】:C++中的STL序列式容器vector源码剖析

⛅️一 vector概述 vector的使用语法可以参考文章&#xff1a;​ 总的来说&#xff1a;vector是可变大小数组 特点&#xff1a; 支持快速随机访问。在尾部之外的位置插入或删除元素可能很慢 元素保存在连续的内存空间中&#xff0c;因此通过下标取值非常快 在容器中间位置添加…

自研OS,手机厂商的「私心」与软件厂商的「灾难」

作者 | 辰纹 来源 | 洞见新研社 在卷完了配置参数&#xff0c;影像跑分&#xff0c;屏幕快充、存储影像、续航折叠……手机还能怎么卷&#xff1f; 过去的2023年&#xff0c;手机厂商们不约而同的将目标瞄准了自研系统。 站在民族情感层面&#xff0c;中国手机“去安卓化”…

Springboot+vue学生考试系统

Springbootvue学生考试系统 演示视频 【Springbootvue学生考试系统】 https://www.bilibili.com/video/BV1gk4y1Q7em/?share_sourcecopy_web&vd_source11344bb73ef9b33550b8202d07ae139b 主要功能&#xff1a; 管理员可以添加题库分配课程教师&#xff0c;指定考试范围指定…

SpringMVC拦截器 (Interceptor)

什么是拦截器 Spring MVC中的拦截器&#xff08;Interceptor&#xff09;类似于Servlet中的过滤器&#xff08;Filter&#xff09;&#xff0c;它主要用于拦截用户请求并作相应的处理。例如通过拦截器可以进行权限验证、判断用户是否登录等。 拦截器依赖于web框架&#xff0c;在…

二极管选型怎么选?常用参数要熟练~

同学们大家好&#xff0c;今天我们继续学习杨欣的《电子设计从零开始》&#xff0c;这本书从基本原理出发&#xff0c;知识点遍及无线电通讯、仪器设计、三极管电路、集成电路、传感器、数字电路基础、单片机及应用实例&#xff0c;可以说是全面系统地介绍了电子设计所需的知识…

多无人机集群智能flocking

matlab2020可运行 GitHub - pareshbhambhani/MultiAgent-Flocking-framework: This is part of the current research I am working on.

响应式Web开发项目教程(HTML5+CSS3+Bootstrap)第2版 例3-1 CSS3过渡

代码 <!doctype html> <html> <head> <meta charset"utf-8"> <title>CSS3 过渡</title> <style> /*显示*/ .box {width: 100px;height: 100px;background-color: #eee;/*透明度*/opacity: 1;/*过渡*/transition: 3s; } /…

leetcode17 电话号码的字母组合

方法1 if-else方法 if-else方法的思路及其简单粗暴&#xff0c;如下图所示&#xff0c;以数字234为例&#xff0c;数字2所对应的字母是abc&#xff0c;数字3所对应的是def&#xff0c;数字4所对应的是ghi&#xff0c;最后所产生的结果就类似于我们中学所学过的树状图一样&…

Windows下Jenkins自动化部署SpringBoot应用

Windows下Jenkins自动化部署SpringBoot应用 1、下载安装包 下载地址&#xff1a; 一个是 msi 程序&#xff1a; https://mirrors.aliyun.com/jenkins/windows/ 一个是 war 程序&#xff1a; https://get.jenkins.io/war-stable/ https://mirrors.jenkins.io/war/ 这里我…

活动 | Mint Blockchain 将于 2024 年 1 月 17 号启动 MintID 限量发行活动

MintID 是 Mint Blockchain 生态的超级权益卡&#xff0c;用于探索 NFT PASS 在未来各种应用场景下的可能性。MintID 将通过限时限量有价发售的方式对外释放&#xff0c;持有人将成为 Mint Blockchain 的核心权益用户。 MintID 总量&#xff1a;10,000 枚 铸造价格&#xff1a…

Go 语言 panic 和 recover 详解

panic() 和 recover() 是 Go 语言中用于处理错误的两个重要函数。panic() 函数用于中止程序并引发panic&#xff0c;而 recover() 函数用于捕获panic并恢复程序的执行。 什么是panic和recover&#xff1f; panic panic() 函数用于中止程序并引发panic。panic() 函数可以接收…