设计模式之建造者模式:灵活可扩展的对象创建过程

目录

一、什么是建造者模式

二、建造者模式的应用场景

三、建造者模式的优缺点

3.1. 优点

3.2. 缺点

四、建造者模式示例

4.1. 问题描述

4.2. 问题分析

4.3. 代码实现

五、建造者模式的另一种实现方式

六、总结


一、什么是建造者模式

    建造者模式(Builder Pattern)是一种创建型设计模式(Creational Pattern),可以将部件和其组装过程分开,一步一步创建一个复杂的对象。用户只需要指定复杂对象的类型就可以得到该对象,而无须知道其内部的具体构造细节。它提供了一种更加灵活和可扩展的方式来创建对象,同时也避免了构造函数参数过多导致的代码可读性和维护性问题。

    建造者模式主要包含以下四类角色:

  • 产品(Product):表示被构建的复杂对象。通常包含多个部分,具体部分的创建由具体建造者负责。
  • 抽象建造者(Builder):定义了创建产品各个部分的抽象接口,以及返回产品的方法。
  • 具体建造者(Concrete Builder):实现了抽象建造者接口,负责具体部分的创建,并返回一个组装好的产品。
  • 指挥者(Director):调用具体建造者来创建产品对象,并控制构建过程的顺序。

二、建造者模式的应用场景

        建造者模式创建的是复杂对象,其产品的各个部分经常面临较大变化,但将它们组合在一起的算法却相对稳定,所以它适用于以下情况:

  • 当对象的构建过程较为复杂,包含多个步骤或者需要按照一定顺序构建时。
  • 当需要创建的对象具有多个表示,但构建过程相同时,可以使用建造者模式。
  • 当需要创建的对象具有复杂的内部结构,且需要按照一定的步骤进行构造时,可以使用建造者模式。

三、建造者模式的优缺点

3.1. 优点

  • 封装性:建造者模式将对象的构建过程和表示过程分离,客户端只需要知道产品的类型以及包含哪些部分,而不需要知道内部的具体构建细节。这样可以更好地封装对象,提高代码的可读性和可维护性。
  • 可扩展性:建造者模式允许在不修改已有代码的情况下扩展新的产品部件,只需要增加新的具体建造者类即可。这样可以提高系统的可扩展性,降低维护成本。
  • 清晰性:通过将构建过程分解为多个步骤,使得构建过程更加清晰,便于维护和理解。
  • 灵活性:客户端不必知道产品内部组成的细节,建造者可以对创建过程逐步细化,而不对其它模块产生任何影响。

3.2. 缺点

  • 产品的组成部分必须相同:建造者模式要求所有产品都具有相同的组成部分,这在一定程度上限制了其使用范围。如果某些产品需要特殊的构建过程或者组成部分不同,那么这种模式可能就不适用。
  • 产品内部变化复杂时维护成本较高:如果产品的内部变化复杂,那么当产品内部发生变化时,所有的Builder类都需要同步修改,这可能会导致维护成本较高。

四、建造者模式示例

4.1. 问题描述

    假设我们要制造一辆汽车,汽车由车身、引擎、轮胎等部件组成。汽车的不同部件都有不同的规格可供选择,如何通过代码来实现汽车的构建过程。

4.2. 问题分析

    问题的目的是要通过代码来创建汽车的实例对象,汽车的组成都是由车身、引擎等部件构成,只是不同部件有不同的表示(规格),这就符合了建造者模式的使用场景。问题当中的汽车(Car)显然就是我们建造者模式中的产品(Product),汽车中需要有多个部件:车身(body)、引擎(engine)、轮胎(tire),为了统一创建汽车的功能接口,我们定义其抽象建造者(Builder)为汽车建造者(CarBuilder),最后定义一个汽车建造指挥者(CarDirector)用来协调建造过程,当我们有了一个新的产品时,就可以通过新增一个汽车创建者的实现类来完成新产品的组成定义,比如有一个汽车产品A,其车身为碳纤维(carbon fibre)的,引擎是电动的(electric),轮胎是充气橡胶的(inflatable rubber),那么我们就可以新增一个A款汽车的建造者(CarABuilder)来实现这款汽车对象的创建。

4.3. 代码实现

    经过上一步的分析之后,下面我们通过代码来实现它:

/*** 定义汽车类*/
class Car{private String body;private String engine;private String tire;
​public String getBody() {return body;}
​public void setBody(String body) {this.body = body;}
​public String getEngine() {return engine;}
​public void setEngine(String engine) {this.engine = engine;}
​public String getTire() {return tire;}
​public void setTire(String tire) {this.tire = tire;}
}
​
/*** 汽车创建者接口*/
interface CarBuilder{void buildBody();void buildEngine();void buildTire();Car getCar();
}
​
/*** 汽车创建指挥者*/
class CarDirector{private final CarBuilder carBuilder;public CarDirector(CarBuilder carBuilder){this.carBuilder = carBuilder;}public Car construct(){carBuilder.buildBody();carBuilder.buildEngine();carBuilder.buildTire();return carBuilder.getCar();}
}
​
/*** A型号汽车创建者*/
class CarABuilder implements CarBuilder{private final Car car = new Car();@Overridepublic void buildBody() {car.setBody("carbon fibre");}@Overridepublic void buildEngine() {car.setEngine("electric");}@Overridepublic void buildTire() {car.setTire("inflatable rubber");}@Overridepublic Car getCar() {return car;}
}

    当我们需要创建一个A型号的汽车的对象时,我们只需要这样做就可以了:

Car carA = new CarDirector(new CarABuilder()).construct();

五、建造者模式的另一种实现方式

    当一个对象的属性过多时,通过常规的实例化方法实现的代码的可读性会非常差,并且还需要使用者对内部的所有属性都有一定的了解,此时我们可以通过给这个类专门写一个内部类作为建造者的方式将一些创建逻辑或者约束条件封装到建造者内部,使使用者可以较为简单地创建复杂对象。

    我们以java.util包下的抽象类Calendar为例,打开Calendar类,我们可以发现里面有大量的属性:

    并且作为抽象类,Calendar类还会有不同的实现:

    如果没有建造者的话,在创建一个Calendar的对象的时候无疑是很头疼的。所以Calendar类内部为我们提供了一个建造者:

    通过这个建造者我们就可以很轻松地创建一个Calendar类的实例了:

Calendar.Builder builder = new Calendar.Builder();
builder.setCalendarType("iso8601");
builder.setDate(2024, 3, 6);
Calendar calendar = builder.build();
System.out.println(calendar.getTime());

六、总结

    建造者模式是一种非常有用的设计模式,它可以帮助我们更好地组织复杂对象的构建过程,提高代码的可读性和可维护性。通过将构建过程与表示分离,建造者模式使得对象的创建变得更加灵活和可控。在实际项目中,我们可以根据具体需求来选择是否使用建造者模式,以提高代码的质量和可扩展性。

    希望通过本文的介绍,您对建造者模式有了更深入的理解,能够在实际项目中灵活运用。谢谢阅读!

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

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

相关文章

016——DHT11驱动开发(基于I.MX6uLL)

目录 一、 模块介绍 1.1 简介 1.2 电路描述 1.3 通信协议 二、 驱动程序 三、 应用程序 四、 上机实验 一、 模块介绍 1.1 简介 DHT11 是一款可测量温度和湿度的传感器。比如市面上一些空气加湿器,会测量空气中湿度,再根据测量结果决定是否继续加…

Vue-Router入门

现在的前后端分离项目,后端只管数据传递,视图跳转的活交由前端来干了,vue-router就是专门来干这个活的,它可以让页面跳转到指定组件 组件是可复用的 Vue 实例, 把一些公共的模块抽取出来,然后写成单独的的工具组件或者…

基于沙漏 Tokenizer 的高效三维人体姿态估计框架HoT

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 摘要Abstract文献阅读:基于沙漏 Tokenizer 的高效三维人体姿态估计框架HoT1、研究背景2、提出方法3、模块详细3.1、什么是HoT3.2、HoT 框架3.3、Token 剪…

SQL语句的编写

##创建用户-建表建库 #创建一个用户名为 feng,允许从任何主机 % 连接,并使用密码 sc123456 进行身份验证的用户。 rootTENNIS 16:33 scmysql>create user feng% identified by sc123456; Query OK, 0 rows affected (0.04 sec) #创建一个名为fen…

京东云16核64G云服务器租用优惠价格500元1个月、5168元一年,35M带宽

京东云16核64G云服务器租用优惠价格500元1个月、5168元一年,35M带宽,配置为:16C64G-450G SSD系统盘-35M带宽-8000G月流量 华北-北京,京东云活动页面 yunfuwuqiba.com/go/jd 活动链接打开如下图: 京东云16核64G云服务器…

215 基于matlab的快速跟踪算法

基于matlab的快速跟踪算法,提出一种简单又快速、 鲁棒性的算法,基于贝叶斯框架下,该模型 (即图像强度和从目标位置) 的低级功能及周边地区的统计相关性的时空关系。跟踪问题是通过计算信心地图,并将以最大限…

springboot国际化多语言

1,新建国际化多语言文件 在resources目录下新建 messages.properties 其他语言的文件 编辑messages.properties文件,下方从text切换到Resource Bundle ,即可对照着编辑多语言文件 (如果没有找到Resource Bundle,先在settings->plugins中安装Resource Bundle Editor) 2,配…

Lanelets_ 高效的自动驾驶地图表达方式

Lanelets: 高效的自动驾驶地图表达方式 附赠自动驾驶学习资料和量产经验:链接 LaneLets是自动驾驶领域高精度地图的一种高效表达方式,它以彼此相互连接的LaneLets来描述自动驾驶可行驶区域,不仅可以表达车道几何,也可以完整表述车…

Django之五种中间件定义类型—process_request、process_view、process_response.......

目录 1. 前言 2. 基础中间件 3. 如何自定义中间件 4. 五种自定义中间件类型 4.1 process_request 4.2 process_view 4.3 process_response 4.4 process_exception 4.5 process_template_response 5. 最后 1. 前言 哈喽,大家好,我是小K,今天咋们…

数据可视化-地图可视化-Python

师从黑马程序员 基础地图使用 基础地图演示 视觉映射器 具体颜色对应的代码可以在http://www.ab173.com/中查询RGB颜色查询对照表 from pyecharts.charts import Map from pyecharts.options import VisualMapOpts#准备地图对象 mapMap() #准备数据 data[("北京",…

Flutter开发进阶之错误信息

Flutter开发进阶之错误信息 在Flutter开发中错误信息通常是由Exception和Error表示,Error表示严重且不可恢复的错误,一般会导致程序直接终止,而Exception可以被显式抛出,一般为代码逻辑错误,根据Flutter的解释说Excep…

Golang开发2D小游戏全套教程(已完结)

Golang开发2D小游戏全套教程(已完结) 本套教程将基于ebiten库开发一套2D小游戏。 全套代码:https://github.com/ziyifast/ziyifast-code_instruction/tree/main/game_demo ebiten官网地址:https://github.com/hajimehoshi/ebiten …