设计模式(java)- 建造者模式

2024-06-22 16:48

本文主要是介绍设计模式(java)- 建造者模式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 简介

  建造者模式,借用百度百科的解释:建造者模式是设计模式的一种,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
  如上,可以看出来建造者模式属于创建型模式的一种,它的作用主要是:

  1. 将类对象的创建过程和细节封装起来,客户代码只需要知道自己建造对象的建造者是谁就可以获取到自己需要的类对象。
  2. 根据客户代码的需求可以通过相同的创建顺序和逻辑创建出拥有相同成员类型但是不同成员值的类对象。

2. 类图

  UML是帮助我们理解设计模式最好的工具,下面是一个基本的创建者模式的设计类图:
在这里插入图片描述
  如上对类图的各个模块进行说明:

  1. 指挥者类Direct,暴露给客户的类,客户创建一个对象时只需要与这个类交互就可以。
  2. 指挥类是提供给客户的接口类,指挥者中的接口一般是构建产品的方法,该方法的形参一般是具体的构建者对象。所以客户还需要关注的是构建者类(类似于工厂类),它就是客户的需求类,客户需要什么样的产品就传入对应的构建者类对象。
  3. 构建者类,拥有共同的抽象接口(IBuilder),根据不同的产品部件设计不同的创建者类(ConcretelBuilder)
  4. 产品类(Product),最终客户需要的产品对象,具体有构建者类进行构建。

3. 实例

3.1 场景

  一家手机代理制造商,自然有自己的手机制造工厂,类似于富士康。手机产品公司A要求代理商生产出如下的产品参数的手机。

CPU: Qualcomm Snapdragon 845
RAM: 8GB
ROM: 64GB
Battery: 3400mAh
Screen: Corning Gorilla Sixth Generation Screen
System: android8.1

3.2 代码实例

3.2.1 产品类

  根据如上的场景,我们可以设计一个手机产品类如下:

class EPhone {private String cpu;private String ram;private String rom;private String battery;private String screen;private String system;public EPhone() {this.cpu = "";this.ram = "";this.rom = "";this.battery = "";this.screen = "";this.system = "";}public void setCpu(String strCpu) {this.cpu = strCpu;}public void setRam(String strRam) {this.ram = strRam;}public void setRom(String strRom) {this.rom = strRom;}public  void setBattery(String strBattery) {this.battery = strBattery;}public void setScreen(String strScreen) {this.screen = strScreen;}public void setSystem(String strSystem) {this.system = strSystem;}public String getSystem() {return this.system;}//...
}

  该例子主要为了说明创建者模式,所以会省略一些代码。

3.2.1 创建者类

  有了产品类,那么需要一个建造者类,用于对产品的具体构建,这一步主要作用的封装产品的构建逻辑,以及根据产品需求不同的产品部件(部件类型相同,主要体现在部件的内部属性或逻辑),设计不同的建造类。
   根据以上的说明,建者者类有许多,所以需要抽象接口类或抽象类。

interface IPhoneBuilder {public void buildCpu();public void buildRam();public void buildRom();public void buildBattery();public void buildScreen();public void buildSystem();public EPhone createPhone();
}

  如上,建造者接口提供了建造产品各个部件的方法,以及最终生产出具体产品的方法:

public EPhone createPhone()

  下面代理商就需要根据A手机公司设计具体的建造者类了,定位该手机为A手机公司的高配版:

class EHighVersionPhoneBuilder implements IPhoneBuilder {private EPhone highPhone = null;public EHighVersionPhoneBuilder() {highPhone = new EPhone();}public void buildCpu() {highPhone.setCpu("Use Qualcomm Snapdragon 845");}public void buildRam() {highPhone.setRam("Use 8GB RAM");}public void buildRom() {highPhone.setRom("Use 64GB ROM");}public void buildBattery() {highPhone.setBattery("Use 3400 mAh battery");}public void buildScreen() {highPhone.setScreen("Use Corning Gorilla Sixth Generation Screen");}public void buildSystem() {highPhone.setSystem("Use android8.1 operating system");}public EPhone createPhone() {return highPhone;}
}

3.2.2 指挥类

  创建类设计完成后,客户代码本可以直接根据建造者类直接得到自己所需要的产品对象,但是我们会发现这个时候客户需要知道该产品的构建顺序是什么样的,那么客户就会写下如下的代码:

EHighVersionPhoneBuilder highVersionPhoneBuilder = new EHighVersionPhoneBuilder();
highVersionPhoneBuilder .buildCpu();
highVersionPhoneBuilder .buildRam();
highVersionPhoneBuilder .buildRom();
highVersionPhoneBuilder .buildBattery();
highVersionPhoneBuilder .buildScreen();
highVersionPhoneBuilder .buildSystem();
highVersionPhoneBuilder .createPhone();

  问题来了,这么多个接口方法,如果构建顺序发生变化,客户就需要跟着去修改代码,如果这块代码在很多处都有使用,那改起来很麻烦,也违背了开闭原则。所以这个时候我们需要一个指挥者类,来控制产品构建的顺序。

class EPhoneDirector {public static EPhone createPhone(IPhoneBuilder phoneBuilder) {if (phoneBuilder != null) {phoneBuilder.buildCpu();phoneBuilder.buildRam();phoneBuilder.buildRom();phoneBuilder.buildBattery();phoneBuilder.buildScreen();phoneBuilder.buildSystem();return phoneBuilder.createPhone();}return null;}
}

3.2.3 客户调用

  如下是客户创建一个高配版手机的过程:

public class EBuilder {public static void main(String[] args) {// TODO Auto-generated method stubEHighVersionPhoneBuilder highVersionPhoneBuilder = new EHighVersionPhoneBuilder();EPhone highPhone = EPhoneDirector.createPhone(highVersionPhoneBuilder);System.out.println(highPhone.getSystem()); }}

  我们会发现需要客户需要获取一个产品对象,只需要关注两个类,一个是指挥者类,一个是具体的建造类。

3.2.4 实例扩展

  至此,一个建造者模式的基本架构就出来了,那么当A公司又需要一个低配版的手机,怎么办呢,我们只需要拿到A公司提供的低配版参数,创建一个低配版的建造类就可以了。同理,A公司需要一个NFC版本的手机,其他参数和高配版一样,那么手机类新增一个NFC的设计方法,高配构建者新增一个nfc的构建接口,然后在指挥类加一个构建NFC高配版的方法就可以了:

class EPhoneDirector {public static EPhone createNfcPhone(IPhoneBuilder phoneBuilder) {if (phoneBuilder != null) {phoneBuilder.buildCpu();phoneBuilder.buildRam();phoneBuilder.buildRom();phoneBuilder.buildBattery();phoneBuilder.buildScreen();phoneBuilder.buildSystem();phoneBuilder.buildNfc();	return phoneBuilder.createPhone();}return null;}
}

  在这个建造者模式的架构中,我们可以根据具体需求灵活的使用,这样客户对产品的构建就会很方便,方便了代码的重用性。

4. 总结

4.1 优缺点

优点:

  1. 解耦,低耦合。客户代码不需要关注产品的创建逻辑和顺序。
  2. 扩展性好,根据客户的需求,可以扩展不同的建造者类或者根据产品创建的顺序的不同,新增不同的指挥方法,符合开闭原则。
  3. 便于控制内部细节和逻辑,便于维护。

缺点:

  1. 局限性:产品本身的局限性,一般需要构建的产品之间又相同或较多的共同点,产品的组成结构相同。这种局限性使得建造者模式的使用场景相对较少,当产品的差异性很大时,例如手机和电脑,这样则不适合使用该模式。
  2. 有类膨胀的理论风险:当产品类型很多时,我们就需要设计多个建造者类,这样会造成类过多的问题,该问题同样体现在工厂方法中。但是一班情况下不会出现这种情况。

  以上就是我对创建者模式的理解,创建者模式很少在项目中使用,但是如果遇到具体的业务,使用它还是会很方便我们程序的设计。总之具体问题具体分析,能够根据不同的业务场景来使用不同的设计模式,那就是好的设计。

设计模式代码:
https://github.com/eaikao/DesignPatterns.git

这篇关于设计模式(java)- 建造者模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1084852

相关文章

SpringBoot使用Apache Tika检测敏感信息

《SpringBoot使用ApacheTika检测敏感信息》ApacheTika是一个功能强大的内容分析工具,它能够从多种文件格式中提取文本、元数据以及其他结构化信息,下面我们来看看如何使用Ap... 目录Tika 主要特性1. 多格式支持2. 自动文件类型检测3. 文本和元数据提取4. 支持 OCR(光学

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J

JAVA系统中Spring Boot应用程序的配置文件application.yml使用详解

《JAVA系统中SpringBoot应用程序的配置文件application.yml使用详解》:本文主要介绍JAVA系统中SpringBoot应用程序的配置文件application.yml的... 目录文件路径文件内容解释1. Server 配置2. Spring 配置3. Logging 配置4. Ma

Java 字符数组转字符串的常用方法

《Java字符数组转字符串的常用方法》文章总结了在Java中将字符数组转换为字符串的几种常用方法,包括使用String构造函数、String.valueOf()方法、StringBuilder以及A... 目录1. 使用String构造函数1.1 基本转换方法1.2 注意事项2. 使用String.valu

java脚本使用不同版本jdk的说明介绍

《java脚本使用不同版本jdk的说明介绍》本文介绍了在Java中执行JavaScript脚本的几种方式,包括使用ScriptEngine、Nashorn和GraalVM,ScriptEngine适用... 目录Java脚本使用不同版本jdk的说明1.使用ScriptEngine执行javascript2.

Spring MVC如何设置响应

《SpringMVC如何设置响应》本文介绍了如何在Spring框架中设置响应,并通过不同的注解返回静态页面、HTML片段和JSON数据,此外,还讲解了如何设置响应的状态码和Header... 目录1. 返回静态页面1.1 Spring 默认扫描路径1.2 @RestController2. 返回 html2

Spring常见错误之Web嵌套对象校验失效解决办法

《Spring常见错误之Web嵌套对象校验失效解决办法》:本文主要介绍Spring常见错误之Web嵌套对象校验失效解决的相关资料,通过在Phone对象上添加@Valid注解,问题得以解决,需要的朋... 目录问题复现案例解析问题修正总结  问题复现当开发一个学籍管理系统时,我们会提供了一个 API 接口去

Java操作ElasticSearch的实例详解

《Java操作ElasticSearch的实例详解》Elasticsearch是一个分布式的搜索和分析引擎,广泛用于全文搜索、日志分析等场景,本文将介绍如何在Java应用中使用Elastics... 目录简介环境准备1. 安装 Elasticsearch2. 添加依赖连接 Elasticsearch1. 创

Spring核心思想之浅谈IoC容器与依赖倒置(DI)

《Spring核心思想之浅谈IoC容器与依赖倒置(DI)》文章介绍了Spring的IoC和DI机制,以及MyBatis的动态代理,通过注解和反射,Spring能够自动管理对象的创建和依赖注入,而MyB... 目录一、控制反转 IoC二、依赖倒置 DI1. 详细概念2. Spring 中 DI 的实现原理三、

SpringBoot 整合 Grizzly的过程

《SpringBoot整合Grizzly的过程》Grizzly是一个高性能的、异步的、非阻塞的HTTP服务器框架,它可以与SpringBoot一起提供比传统的Tomcat或Jet... 目录为什么选择 Grizzly?Spring Boot + Grizzly 整合的优势添加依赖自定义 Grizzly 作为