对建造者模式的理解

目录

  • 一、为什么需要建造者模式?
    • 1、场景1
    • 2、场景2
    • 3、解决上述场景的办法:建造者模式
  • 二、练习
    • 1、题目描述 【[来源](https://kamacoder.com/problempage.php?pid=1084)】
    • 2、输入描述
    • 3、输出描述
    • 4、输入示例
    • 5、输出示例
    • 6、参考
  • 三、思考
    • 1、一般常用的是lombok库的@Builder注解。
    • 2、但@Builder注解有很多坑点
    • 3、不如用@Accessors(chain = true)

一、为什么需要建造者模式?

  • 什么时候使用建造者模式?

1、场景1

  • 有时候,一个类中有很多字段,或者有些字段也是引用类型。这时候,当我们实例化这个类时(建造这个类的对象时),会比较麻烦:
  • 方案:提供入参巨多的构造器
public class ComplexClass {private String name;private String email;private Integer age;private Pet pet;...public ComplexClass(String name, String email, ...) {}
}

2、场景2

  • 有各种各样的房子,它们有一些共同的属性,也有一些独特的属性。
  • 一种设计是:抽象父类 + 多个子类。
  • 这可能导致子类爆炸,明明也是房子对象,却不得不搞一个新的房子类。

3、解决上述场景的办法:建造者模式

  • 示例:
public class House { private List<Wall> walls;private List<Door> doors;...
}public interface IHouseBuilder {void buildWalls(List<Wall> walls);void buildDoors(List<Door> doors);...House getProduct();
}public class HouseWithGarageBuilder implements IHouseBuilder {private House house;public HouseWithGarageBuilder() {house = new House();}public buildWalls(List<Wall> walls) {this.walls = walls;}public buildDoors(List<Door> doors) {this.doors = doors;	}...public House getProduct() {return house;}
}public class HouseDirector {private IHouseBuilder builder;public HouseDirector(IHouseBuilder builder) {this.builder = builder;}public House constructHouse() {builder.buildWalls(...);builder.buildDoors(...);return builder.getProduct();}
}
  • 本质:分步骤建造对象。

二、练习

1、题目描述 【来源】

小明家新开了一家自行车工厂,用于使用自行车配件(车架 frame 和车轮 tires )进行组装定制不同的自行车,包括山地车和公路车。
山地车使用的是Aluminum Frame(铝制车架)和 Knobby Tires(可抓地轮胎),公路车使用的是 Carbon Frame (碳车架)和 Slim Tries。
现在它收到了一笔订单,要求定制一批自行车,请你使用【建造者模式】告诉小明这笔订单需要使用那些自行车配置吧。

2、输入描述

输入的第一行是一个整数 N(1 ≤ N ≤ 100),表示订单的数量。
接下来的 N 行,每行输入一个字符串,字符串表示客户的自行车需求。
字符串可以包含关键词 “mountain” 或 “road”,表示客户需要山地自行车或公路自行车。

3、输出描述

对于每笔订单,输出该订单定制的自行车配置。

4、输入示例

3
mountain
road
mountain

5、输出示例

Aluminum Frame Knobby Tires
Carbon Frame Slim Tires
Aluminum Frame Knobby Tires

6、参考

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Bike {private Frame frame;private Tires tires;@Overridepublic String toString() {return frame.getType() + " " + tires.getType();}
}@Data
@NoArgsConstructor
@AllArgsConstructor
public class Frame {private String type;
}@Data
@NoArgsConstructor
@AllArgsConstructor
public class Tires {private String type;
}public interface IBikeBuilder {void buildFrame();void buildTires();Bike getProduct();
}public class MountainBikeBuilder implements IBikeBuilder {private Bike bike;public MountainBikeBuilder() {bike = new Bike();}@Overridepublic void buildFrame() {bike.setFrame(new Frame("Aluminum Frame"));}@Overridepublic void buildTires() {bike.setTires(new Tires("Knobby Tires"));}@Overridepublic Bike getProduct() {return bike;}
}public class RoadBikeBuilder implements IBikeBuilder {private Bike bike;public RoadBikeBuilder() {bike = new Bike();}@Overridepublic void buildFrame() {bike.setFrame(new Frame("Carbon Frame"));}@Overridepublic void buildTires() {bike.setTires(new Tires("Slim Tries"));}@Overridepublic Bike getProduct() {return bike;}
}public class BikeDirector {public Bike constructBike(IBikeBuilder bikeBuilder) {bikeBuilder.buildFrame();bikeBuilder.buildTires();return bikeBuilder.getProduct();}
}public class Main {public static void main(String[] args) {BikeDirector bikeDirector = new BikeDirector();Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();scanner.nextLine();for (int i = 0; i < n; i++) {String type = scanner.nextLine();IBikeBuilder bikeBuilder;if ("mountain".equals(type)) {bikeBuilder = new MountainBikeBuilder();} else if ("road".equals(type)) {bikeBuilder= new RoadBikeBuilder();} else {throw new RuntimeException("type error");}Bike bike = bikeDirector.constructBike(bikeBuilder);System.out.println(bike.toString());}}
}

三、思考

  • 现实情况下,我还没这么用过建造者模式,因为按照上面的写法,还是很费劲的。

1、一般常用的是lombok库的@Builder注解。

  • 示例:
@Builder
@ToString
public class User {private String name;private Integer age;private String email;private String gender;
}public class Main {public static void main(String[] args) {User user = User.builder().name("Forrest").age(20).email("forrest@qq.com").gender("male").build();System.out.println(user);}
}

这种建造对象的写法看起来还是很舒服的。

  • 编译后的User.class
public class User {private String name;private Integer age;private String email;private String gender;User(String name, Integer age, String email, String gender) {this.name = name;this.age = age;this.email = email;this.gender = gender;}public static UserBuilder builder() {return new UserBuilder();}public String toString() {return "User(name=" + this.name + ", age=" + this.age + ", email=" + this.email + ", gender=" + this.gender + ")";}public static class UserBuilder {private String name;private Integer age;private String email;private String gender;UserBuilder() {}public UserBuilder name(String name) {this.name = name;return this;}public UserBuilder age(Integer age) {this.age = age;return this;}public UserBuilder email(String email) {this.email = email;return this;}public UserBuilder gender(String gender) {this.gender = gender;return this;}public User build() {return new User(this.name, this.age, this.email, this.gender);}public String toString() {return "User.UserBuilder(name=" + this.name + ", age=" + this.age + ", email=" + this.email + ", gender=" + this.gender + ")";}}
}
  • 可以清楚地看到,User中生成了一个内部类UserBuilder,来分步骤设置字段。

2、但@Builder注解有很多坑点

  • 显而易见的一点:
@Builder
@ToString
public class User {private String name = "Forrest";private Integer age;private String email;private String gender;
}public class Main {public static void main(String[] args) {User user = User.builder().age(20).email("forrest@qq.com").gender("male").build();System.out.println(user);}
}User(name=null, age=20, email=forrest@qq.com, gender=male)
  • 默认值就这样丢了…
@Builder
@ToString
@AllArgsConstructor
public class User {private String name = "Forrest";private Integer age;private String email;private String gender;public User(Integer age, String email, String gender) {this.age = age;this.email = email;this.gender = gender;}
}public class Main {public static void main(String[] args) {User user = new User(20, "forrest@qq.com", "male");System.out.println(user);}
}User(name=Forrest, age=20, email=forrest@qq.com, gender=male)
  • 不得不加上@AllArgsConstructor,因为@Builder生成的UserBuilder中用到了全参构造器。

3、不如用@Accessors(chain = true)

@Data
@Accessors(chain = true)
public class User {private String name = "Forrest";private Integer age;private String email;private String gender;
}public class Main {public static void main(String[] args) {User user = new User().setAge(18).setEmail("forrest@qq.com").setGender("male");System.out.println(user);}
}User(name=Forrest, age=18, email=forrest@qq.com, gender=male)

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

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

相关文章

vue 实现下载pdf格式的文件

第一步 安装下载插件 npm install html2canvas jspdf --save第二步 给vue原型上面挂载一个下载页面pdf的方法&#xff1b;在项目工具方法存放文件夹utils中创建htmlToPdf.js文件&#xff0c;代码如下 // 导出页面为PDF格式 import html2Canvas from html2canvas import JsP…

Linux第78步_使用原子整型操作来实现“互斥访问”共享资源

使用原子操作来实现“互斥访问”LED灯设备&#xff0c;目的是每次只允许一个应用程序使用LED灯。 1、创建MyAtomicLED目录 输入“cd /home/zgq/linux/Linux_Drivers/回车” 切换到“/home/zgq/linux/Linux_Drivers/”目录 输入“mkdir MyAtomicLED回车”&#xff0c;创建MyA…

Jmeter---分布式

分布式&#xff1a;多台机协作&#xff0c;以集群的方式完成测试任务&#xff0c;可以提高测试效率。 分布式架构&#xff1a;控制机&#xff08;分发任务&#xff09;与多台执行机&#xff08;执行任务&#xff09; 环境搭建&#xff1a; 不同的测试机上安装 Jmeter 配置基…

2024最新手赚手机软件APP下载排行网站源码及应用商店源码

这是一款简洁蓝色的手机软件下载应用排行、平台和最新发布网站&#xff0c;采用响应式织梦模板。主要包括主页、APP列表页、APP详情介绍页、新闻资讯列表、新闻详情页、关于我们等模块页面。 源码下载&#xff1a;https://download.csdn.net/download/m0_66047725/88898956 更…

政安晨:【深度学习处理实践】(九)—— Transformer架构

咱们接着这个系列的上一篇文章继续&#xff1a; 政安晨&#xff1a;【深度学习处理实践】&#xff08;八&#xff09;—— 表示单词组的两种方法&#xff1a;集合和序列https://blog.csdn.net/snowdenkeke/article/details/136762323 Transformer是一种架构&#xff0c;用于在…

k8s之图形界面DashBoard【九】

文章目录 9. DashBoard9.1 部署Dashboard9.2 使用DashBoard 镇场 9. DashBoard 之前在kubernetes中完成的所有操作都是通过命令行工具kubectl完成的。其实&#xff0c;为了提供更丰富的用户体验&#xff0c;kubernetes还开发了一个基于web的用户界面&#xff08;Dashboard&…

vscode jupyter 如何关闭声音

网上之前搜的zen模式失败 仅仅降低sound失败 #以下是成功方式&#xff1a; 首先确保user和remote的声音都是0&#xff1a; 然后把user和remote的以下设置都设置为off就行了&#xff01; 具体操作参考 https://stackoverflow.com/questions/54173462/how-to-turn-off-or-on-so…

从大模型到Agentscope——分布式Multi-Agent应用开发与部署

目录 Why需要分布式 案例 多进程的分布书版本能快速提升速度 分布式的挑战 AgentScope分布式解决 方案 实现RPC Agent 基于Actor模式的并行调度缺点&#xff1a;需要Agent内部决定消息传递目标 被调用的Agent立即返回占位符placeholder to_dist: 开启自动将单机进行扩展…

5 分钟小工具:使用 dive 分析 docker 镜像

需求 拿到一个镜像之后&#xff0c;我想知道&#xff1a; 分层查看镜像里都有哪些文件各层使用了什么命令构建的这个镜像镜像里比较大的文件有哪些&#xff08;可能需要优化&#xff09; dive 工具介绍 dive 工具可以做这些分析。dive 的 github 地址是 wagoodman/dive&…

观察者模式的理解和引用

1.前言 在之前的H5小游戏中&#xff0c;对于长连接发送的不同类型数据包的处理&#xff0c;是通过switch语句进行处理的&#xff0c;于是在自己的代码中出现了大量的case分支&#xff0c;不方便进行维护和后期的版本迭代。于是在老师的指导下&#xff0c;开始寻求使用观察者模…

SpingBoot集成Rabbitmq及Docker部署

文章目录 介绍RabbitMQ的特点Rabbitmq术语消息发布接收流程 Docker部署管理界面说明Overview: 这个页面显示了RabbitMQ服务器的一般信息&#xff0c;例如集群节点的名字、状态、运行时间等。Connections: 在这里&#xff0c;可以查看、管理和关闭当前所有的TCP连接。Channels: …

Unity Live Capture 中实现面部捕捉同步模型动画

Unity Face Capture 是一个强大的工具&#xff0c;可以帮助你快速轻松地将真实人脸表情捕捉到数字模型中。在本文中&#xff0c;我们将介绍如何在 Unity Face Capture 中实现面部捕捉同步模型动画。 安装 |实时捕获 |4.0.0 (unity3d.com) 安装软件插件 安装 Live Capture 软件…

Linux_网络项目_WEB服务器 处理服务器写入失败后sigpipe信号导致服务器崩溃退出问题,引入线程池缓解大量请求,服务器组件化重构,在线计算机业务测试

文章目录 1. 处理服务器写入管道出错2. 引入线程池缓解大量请求导致服务器崩溃设计线程任务类单例线程池组件设计 3.代码位置4. 在线计算机业务运行截图 1. 处理服务器写入管道出错 经过测试&#xff0c;服务器在读取报文时如果出错可以选择直接关闭这个TCP里链接来节省资源。…

比特币,区块链及相关概念简介(三)

目录 什么是区块链区块链关键特点区块链存在哪里区块链相关的工作主要是做什么呢可以有多个区块链吗区块链网络节点区块链网络有延迟吗区块链和Rust区块链新技术区块链相关网站 以下内容结合了chatgpt 3.5以及网络文章。 用于学习记录。 简介&#xff1a; 什么是区块链&#xf…

【MySQL高级篇】08-事务篇

第13章:事务基础知识 #09-事务的基础知识#1.事务的完成过程 #步骤1&#xff1a;开启事务 #步骤2&#xff1a;一系列的DML操作 #.... #步骤3&#xff1a;事务结束的状态&#xff1a;提交的状态(COMMIT) 、 中止的状态(ROLLBACK)#2. 显式事务#2.1 如何开启&#xff1f; 使用关键…

项目分享--NO.1

搭建高可用的web集群.部署网站 包含数据库,ceph/nfs,haproxy,keepalived,ansible部署 1,配置ansible管理环境 创建工作目录,编写ansible配置文件,和主机清单文件,yum配置文件 将yum文件到控制机上,然后用模块上传到被管理机器上 #vim 01-upload-repo.yml --- - name: confi…

柚见十三期(优化)

前端优化 加载匹配功能与加载骨架特效 骨架屏 : vant-skeleton index.vue中 /** * 加载数据 */ const loadData async () > { let userListData; loading.value true; //心动模式 if (isMatchMode.value){ const num 10;//推荐人数 userListData await myA…

基于SpringBoot框架实现的B2B平台的医疗病历交互系统

采用技术 基于SpringBoot框架实现的B2B平台的医疗病历交互系统的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBootMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 页面展示效果 管理员角色 医院管理 医院注册 医院文…

samba服务器的配置

需求&#xff1a;在Linux上搭建一个文件共享服务&#xff0c;创建不同的账号给予不同的权限&#xff0c;在windows可以直接访问该共享目录 介绍 Samba 是一个强大的工具&#xff0c;使得不同操作系统之间可以无缝地共享文件和资源&#xff0c;促进了跨平台环境下的协作和通信…

音频的录制及播放

在终端安装好pip install pyaudio&#xff0c;在pycharm中敲入录音的代码&#xff0c;然后点击运行可以在10s内进行录音&#xff0c;录音后的音频会保存在与录音代码同一路径项目中&#xff0c;然后再新建项目敲入播放的代码&#xff0c;点击运行&#xff0c;会把录入的录音进行…