重读Java设计模式: 深入探讨建造者模式,构建复杂对象的优雅解决方案

引言

在软件开发中,有时需要构建具有复杂结构的对象,如果直接使用构造函数或者 setter 方法逐个设置对象的属性,会导致代码变得冗长、难以维护,并且容易出错。为了解决这个问题,我们可以使用建造者模式。

一、建造者模式概述

建造者模式是一种创建型设计模式,它的主要目的是将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。这种模式常用于构建具有复杂结构的对象,例如包含多个部件的对象,或者对象的构建过程需要进行多个步骤。

二、建造者模式的结构

建造者模式包含以下几个角色:

  • 产品(Product):要构建的复杂对象,它由多个部件组成。
  • 抽象建造者(Builder):定义了构建产品的抽象方法,具体建造者类将实现这些方法来构建具体的产品。
  • 具体建造者(Concrete Builder):实现了抽象建造者定义的方法,负责构建产品的各个部件,并返回构建后的产品。
  • 指挥者(Director):负责使用建造者构建产品的对象,它通常不了解具体的构建过程,只负责按照指定的步骤调用建造者的方法来构建产品。

三、建造者模式的优点

  • 分步构建:将构建过程分步进行,每一步都由具体建造者负责,可以更加精细地控制构建过程。
  • 隔离复杂性:将构建过程与产品的表示分离,使得构建过程的变化不会影响产品的表示,从而提高了系统的灵活性和可维护性。
  • 复用性:可以使用相同的构建过程来构建不同的产品,提高了代码的复用性。
  • 逐步完善:可以逐步完善构建过程,根据需求的变化灵活地调整构建过程。

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

  • 需要构建的产品具有复杂的内部结构,包含多个部件。
  • 需要构建的产品的构建过程需要进行多个步骤,并且每个步骤的实现方式可能不同。
  • 需要构建的产品的属性之间存在一定的约束关系,需要按照一定的顺序来构建产品。

五、建造者模式的示例代码

我们先来看下相关 UML 图

image-20240331101403448

  • 产品角色
package com.markus.desgin.mode.creational.builder;

/**
 * @Author: zhangchenglong06
 * @Date: 2024/3/7
 * @Description:
 */
public class Car {
  private Wheel wheel;

  private SteeringWheel steeringWheel;

  public Wheel getWheel() {
    return wheel;
  }

  public void setWheel(Wheel wheel) {
    this.wheel = wheel;
  }

  public SteeringWheel getSteeringWheel() {
    return steeringWheel;
  }

  public void setSteeringWheel(SteeringWheel steeringWheel) {
    this.steeringWheel = steeringWheel;
  }

  @Override
  public String toString() {
    return "Car{" +
        "wheel=" + wheel +
        ", steeringWheel=" + steeringWheel +
        '}';
  }
}

package com.markus.desgin.mode.creational.builder;

/**
 * @Author: zhangchenglong06
 * @Date: 2024/3/7
 * @Description:
 */
public interface SteeringWheel {
  String steeringWheel();
}

package com.markus.desgin.mode.creational.builder;

/**
 * @Author: zhangchenglong06
 * @Date: 2024/3/7
 * @Description:
 */
public class XiaomiSteeringWheel implements SteeringWheel {
  @Override
  public String steeringWheel() {
    return "小米轮毂";
  }
}

package com.markus.desgin.mode.creational.builder;

/**
 * @Author: zhangchenglong06
 * @Date: 2024/3/7
 * @Description:
 */
public interface Wheel {
  String wheelType();
}

package com.markus.desgin.mode.creational.builder;

/**
 * @Author: zhangchenglong06
 * @Date: 2024/3/7
 * @Description:
 */
public class XiaomiWheel implements Wheel{
  @Override
  public String wheelType() {
    return "小米方向盘";
  }
}

  • 抽象构建者
package com.markus.desgin.mode.creational.builder;

/**
 * @Author: zhangchenglong06
 * @Date: 2024/3/7
 * @Description:
 */
public abstract class CarBuilder {
  protected Car car = new Car();

  public abstract CarBuilder buildWheel(Wheel wheel);

  public abstract CarBuilder buildSteeringWheel(SteeringWheel steeringWheel);

  public Car builder() {
    return car;
  }
}
  • 具体构建者
package com.markus.desgin.mode.creational.builder;

/**
 * @Author: zhangchenglong06
 * @Date: 2024/3/7
 * @Description:
 */
public class CommonCarBuilder extends CarBuilder {

  @Override
  public CarBuilder buildWheel(Wheel wheel) {
    this.car.setWheel(wheel);
    return this;
  }

  @Override
  public CarBuilder buildSteeringWheel(SteeringWheel steeringWheel) {
    this.car.setSteeringWheel(steeringWheel);
    return this;
  }
}
  • 指挥官
package com.markus.desgin.mode.creational.builder;

/**
 * @Author: zhangchenglong06
 * @Date: 2024/3/7
 * @Description:
 */
public interface Director<T> {
  T construct();
}

package com.markus.desgin.mode.creational.builder;

/**
 * @Author: zhangchenglong06
 * @Date: 2024/3/7
 * @Description: 小米制造商
 */
public class XiaoMiDirector implements Director<Car> {
  private CarBuilder carBuilder;

  public XiaoMiDirector(CarBuilder carBuilder) {
    this.carBuilder = carBuilder;
  }

  @Override
  public Car construct() {
    carBuilder.buildWheel(new XiaomiWheel());
    carBuilder.buildSteeringWheel(new XiaomiSteeringWheel());
    return carBuilder.builder();
  }
}
  • 客户端
package com.markus.desgin.mode.creational.builder;

/**
 * @Author: zhangchenglong06
 * @Date: 2024/3/7
 * @Description:
 */
public class Client {
  public static void main(String[] args) {
    CarBuilder carBuilder = new CommonCarBuilder();
    Director<Car> director = new XiaoMiDirector(carBuilder);
    Car car = director.construct();
    System.out.println(car);
  }
}

六、建造者模式在 Spring 中的应用

在Spring框架中,有几个组件使用了建造者模式的思想来构建复杂对象,其中包括:

  1. RestTemplateBuilderRestTemplateBuilder是用于构建RestTemplate实例的建造者。RestTemplate是Spring提供的用于访问Restful服务的工具类,它支持各种HTTP请求方法和数据交换格式,如JSON和XML。RestTemplateBuilder提供了一系列方法来配置RestTemplate的各种属性,例如连接超时、读取超时、拦截器等,使得构建RestTemplate实例更加灵活和便捷。
  2. WebMvcConfigurerWebMvcConfigurer是Spring MVC框架中的一个接口,用于配置Web MVC的行为。在Spring Boot应用程序中,通常会创建一个实现了WebMvcConfigurer接口的配置类来自定义Web MVC的行为。通过实现WebMvcConfigurer接口,可以通过覆盖其中的方法来配置拦截器、消息转换器、视图解析器等各种组件,从而实现对Spring MVC框架的定制化。这种灵活性和可定制性正是建造者模式的优势之一。
  3. SqlSessionFactoryBean: 在Spring中使用MyBatis进行持久化操作时,通常会配置一个SqlSessionFactoryBean实例来创建SqlSessionFactory对象。SqlSessionFactory是MyBatis框架中的核心接口,用于创建SqlSession对象,通过SqlSession对象可以执行SQL语句并与数据库进行交互。SqlSessionFactoryBean提供了一系列方法来配置MyBatis的各种属性,例如数据源、类型别名、Mapper扫描等,使得创建SqlSessionFactory实例更加灵活和可配置。

这些组件在Spring框架中使用建造者模式的思想,通过提供一系列的配置方法来构建复杂的对象实例,使得对象的创建过程更加灵活和可定制。

七、设计模式百宝箱

在本节,我们开始填充我们的百宝箱:

  • 面向对象基础
    • 抽象
    • 封装
    • 多态
    • 继承
  • 面向对象原则
    • 依赖抽象,不要依赖具体类
    • 针对接口编程,不针对具体实现编程
    • 类应该对扩展开放,对修改关闭
    • 为交互对象之间的松耦合设计而努力
  • 面向对象设计模式
    • 简单工厂模式:定义了一个创建对象的接口,将创建对象的内容从客户端抽离出来
    • 抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类
    • 原型模式:通过复制现有对象来创建新对象,提高代码效率和可维护性
    • 建造者模式:将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示

八、总结

建造者模式是一种创建型设计模式,通过将构建过程与产品的表示分离,使得同样的构建过程可以创建不同的表示。本文介绍了建造者模式的概念、结构、优点、应用场景,并提供了示例代码进行说明。建造者模式可以有效地解决构建复杂对象时的代码冗长、难以维护的问题,是一种值得推荐的设计模式。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Jamba LLM模型:破解大型上下文窗口挑战的AI新星

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

使用Postman进行websocket接口测试

因为最近要搞关于基于AI的文本接口测试.需要用到websocket协议,于是看了一下发现postman也可以测而且很方便 位置 File->New->WebSocket 可以看到不止WebSocket还支持其他的各种协议 使用 首先先点击connect进行连接 连接成功之后可以选择多种文本格式添加请求参数 每…

打开DICOM文件需要注意到的点

DICOM图片用来存储医学信息 我一般处理的是图像信息&#xff0c;总结一下踩过的坑 打开DICOM文件需要注意到的点 DICOM图片使用python进行打开一定要注意窗口问题&#xff0c;dicom文件里面存储了很多其他的附加信息&#xff0c;不仅仅是图片&#xff0c;其中最重要的一个条就…

力扣刷题Days29-128.最长连续数列(js)

目录 1&#xff0c;题目 2&#xff0c;代码 2.1自己实现 2.2哈希表 3&#xff0c;学习与收获 枚举思想&#xff1a; 遍历的核心逻辑 碎碎念 本题 先是想到利用数组排序&#xff0c;从而简化遍历处理逻辑&#xff0c;再在提交错误提醒的情况下&#xff0c;考虑到数组中存…

Tab切换(Html+JavaScript+Css)

1.CSS样式 <style>* {margin: 0;padding: 0;}.tab {width: 590px;height: 340px;margin: 20px;border: 1px solid #e4e4e4;margin-left: 300px;}.tab-nav {width: 100%;height: 60px;line-height: 60px;display: flex;justify-content: space-between;}.tab-nav h3 {font…

Zeppelin安装

Zeppelin是一个基于Web的开源数据分析可视化工具&#xff0c;它提供了一个交互式的笔记本界面&#xff0c;用于在大数据环境中进行数据探索、数据分析、数据可视化和协作。Zeppelin的主要特点包括多语言支持、可视化功能、数据共享和协作&#xff0c;以及扩展性。它支持多种编程…

C++ 数组 结构编程题

一 求100以内的所有素数 /* * 需要标记2~100 之间的数是否处理 * 用数组&#xff0c;初始为0 表示都是素数&#xff0c;如果 判断为合数则置为1过用 */ #include<stdio.h> #include<math.h> int main() {const int n 100;int isPrim[n 1] { 0 };int i, j;for (…

C++ MFC

C是一种静态数据类型检查的、支持多重编程范式的程序设计语言&#xff0c;支持过程化程序设计、数据抽象、面向对象程序设计、制作图标等泛型程序设计的多种程序设计风格。 MFC(Microsoft Foundation Classes)&#xff0c;是一个微软公司提供的类库&#xff0c;以C类的形式封装…

JAVAEE之CSS

1.CSS 是什么&#xff1f; 层叠样式表 (Cascading Style Sheets). CSS 能够对网页中元素位置的排版进行像素级精确控制, 实现美化页面的效果. 能够做到页面的样式和结构分离. 1.1 CSS和HTML的区别 CSS&#xff0c;全称为层叠样式表(Cascading Style Sheets)&#xff0c;是…

【Spring Boot 源码学习】ConditionEvaluationReport 日志记录上下文初始化器

《Spring Boot 源码学习系列》 ConditionEvaluationReport 日志记录上下文初始化器 一、引言二、往期内容三、主要内容3.1 源码初识3.2 ConditionEvaluationReport 监听器3.3 onApplicationEvent 方法3.4 条件评估报告的打印展示 四、总结 一、引言 上篇博文《共享 MetadataRe…

redis和数据库数据不一直问题,缓存常见的三大问题

文章目录 数据一致性缓存常见问题缓存穿透缓存击穿缓存雪崩 数据一致性 1 思路 查询数据的时候&#xff0c;如果缓存未命中&#xff0c;则查询数据库&#xff0c;将数据写入缓存设置超时时间修改数据时&#xff0c;先修改数据库&#xff0c;在删除缓存。 2 代码实现 修改更…

【原创】基于分位数回归的卷积长短期结合注意力机制的神经网络(CNN-QRLSTM-Attention)回归预测的MATLAB实现

基于分位数回归的卷积长短期结合注意力机制的神经网络&#xff08;CNN-QRLSTM-Attention&#xff09;是一种用于时间序列数据预测的深度学习模型。该模型结合了卷积神经网络&#xff08;CNN&#xff09;、长短期记忆网络&#xff08;LSTM&#xff09;和注意力机制&#xff08;A…

P1803 凌乱的yyy / 线段覆盖(贪心)

思路&#xff1a; 这道题让求区间覆盖&#xff0c;它要求只能一个一个的区间&#xff0c;先对n个区间进行排序&#xff0c;按照区间的结束点前后进行排序。所以从后往前看结束时间点&#xff0c;如果下一个的起点在前一个的结束点之后&#xff0c;则数量加1。 代码&#xff1a…

Python进阶编程 --- 1.类和对象

文章目录 第一章&#xff1a;1.初始对象1.1 使用对象组织数据1.2 类的成员方法1.2.1 类的定义和使用1.2.2 创建类对象1.2.3 成员变量和成员方法1.2.4 成员方法的定义语法1.2.5 注意事项 1.3 类和对象1.3.1 基于类创建对象 1.4 构造方法1.5 其他内置方法1.5.1 魔术方法str字符串…

鸿蒙OS开发实战:【网络管理HTTP数据请求】

一、场景介绍 应用通过HTTP发起一个数据请求&#xff0c;支持常见的GET、POST、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT方法。 二、 接口说明 HTTP数据请求功能主要由http模块提供。 使用该功能需要申请ohos.permission.INTERNET权限。 涉及的接口如下表&#xff0c;…

python爬取B站视频

参考&#xff1a;https://cloud.tencent.com/developer/article/1768680 参考的代码有点问题&#xff0c;请求头需要修改&#xff0c;上代码&#xff1a; import requests import re # 正则表达式 import pprint import json from moviepy.editor import AudioFileClip, Vid…

QT初识(2)

QT初识&#xff08;2&#xff09; 创建好项目之后&#xff0c;多了些什么东西&#xff1f;main.cppwidget.hwidget.cppwidget.ui.pro项目工程文件 我们今天来继续了解QT。如果没看过上一次QT初识的小伙伴可以点击这里&#xff1a; https://blog.csdn.net/qq_67693066/article/d…

STM32的DMA

DMA(Direct memory access)直接存储器存取,用来提供在外设和存储器之间或者存储 器和存储器之间的高速数据传输&#xff0c;无须CPU干预&#xff0c;数据可以通过DMA快速地移动&#xff0c;这就节 省了CPU的资源来做其他操作。 STM32有两个DMA控制器共12个通道(DMA1有7个通道…

基于YOLOV8+Pyqt5光伏太阳能电池板目标检测系统

1、YOLOV8算法 YOLOv8 是当前效果较好的目标检测 算法&#xff0c;它的核心网络来源于 DarkNet-53&#xff0c;该网络初次在 YOLOv3[11] 中被引入&#xff0c;并深受 ResNet[12] 的影响。DarkNet-53 使用了残差机制&#xff0c;并连续添加了卷积模块来加强其功能性。 这 53 层…

Cortex‐M3/M4/M7内核的操作模式和特权等级介绍

0 前言 如果我们是基于MCU的裸机编程&#xff0c;是不需要关心内核的操作模式和特权等级的。如果是进行RTOS的开发编程&#xff0c;我们就要必要了解一下Cortex‐M3/M4/M7内核的操作模式和特权等级&#xff0c;这在RTOS的线程切换等场合会使用到。 1 Cortex‐M3/M4/M7内核的操…