设计模式(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

相关文章

Java 实用工具类Spring 的 AnnotationUtils详解

《Java实用工具类Spring的AnnotationUtils详解》Spring框架提供了一个强大的注解工具类org.springframework.core.annotation.Annot... 目录前言一、AnnotationUtils 的常用方法二、常见应用场景三、与 JDK 原生注解 API 的

Java controller接口出入参时间序列化转换操作方法(两种)

《Javacontroller接口出入参时间序列化转换操作方法(两种)》:本文主要介绍Javacontroller接口出入参时间序列化转换操作方法,本文给大家列举两种简单方法,感兴趣的朋友一起看... 目录方式一、使用注解方式二、统一配置场景:在controller编写的接口,在前后端交互过程中一般都会涉及

Java中的StringBuilder之如何高效构建字符串

《Java中的StringBuilder之如何高效构建字符串》本文将深入浅出地介绍StringBuilder的使用方法、性能优势以及相关字符串处理技术,结合代码示例帮助读者更好地理解和应用,希望对大家... 目录关键点什么是 StringBuilder?为什么需要 StringBuilder?如何使用 St

使用Java将各种数据写入Excel表格的操作示例

《使用Java将各种数据写入Excel表格的操作示例》在数据处理与管理领域,Excel凭借其强大的功能和广泛的应用,成为了数据存储与展示的重要工具,在Java开发过程中,常常需要将不同类型的数据,本文... 目录前言安装免费Java库1. 写入文本、或数值到 Excel单元格2. 写入数组到 Excel表格

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

Maven中引入 springboot 相关依赖的方式(最新推荐)

《Maven中引入springboot相关依赖的方式(最新推荐)》:本文主要介绍Maven中引入springboot相关依赖的方式(最新推荐),本文给大家介绍的非常详细,对大家的学习或工作具有... 目录Maven中引入 springboot 相关依赖的方式1. 不使用版本管理(不推荐)2、使用版本管理(推

Java 中的 @SneakyThrows 注解使用方法(简化异常处理的利与弊)

《Java中的@SneakyThrows注解使用方法(简化异常处理的利与弊)》为了简化异常处理,Lombok提供了一个强大的注解@SneakyThrows,本文将详细介绍@SneakyThro... 目录1. @SneakyThrows 简介 1.1 什么是 Lombok?2. @SneakyThrows

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B

如何在 Spring Boot 中实现 FreeMarker 模板

《如何在SpringBoot中实现FreeMarker模板》FreeMarker是一种功能强大、轻量级的模板引擎,用于在Java应用中生成动态文本输出(如HTML、XML、邮件内容等),本文... 目录什么是 FreeMarker 模板?在 Spring Boot 中实现 FreeMarker 模板1. 环

SpringMVC 通过ajax 前后端数据交互的实现方法

《SpringMVC通过ajax前后端数据交互的实现方法》:本文主要介绍SpringMVC通过ajax前后端数据交互的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价... 在前端的开发过程中,经常在html页面通过AJAX进行前后端数据的交互,SpringMVC的controll