设计模式(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编译生成多个.class文件的原理和作用

《Java编译生成多个.class文件的原理和作用》作为一名经验丰富的开发者,在Java项目中执行编译后,可能会发现一个.java源文件有时会产生多个.class文件,从技术实现层面详细剖析这一现象... 目录一、内部类机制与.class文件生成成员内部类(常规内部类)局部内部类(方法内部类)匿名内部类二、

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

Springboot @Autowired和@Resource的区别解析

《Springboot@Autowired和@Resource的区别解析》@Resource是JDK提供的注解,只是Spring在实现上提供了这个注解的功能支持,本文给大家介绍Springboot@... 目录【一】定义【1】@Autowired【2】@Resource【二】区别【1】包含的属性不同【2】@

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

Java枚举类实现Key-Value映射的多种实现方式

《Java枚举类实现Key-Value映射的多种实现方式》在Java开发中,枚举(Enum)是一种特殊的类,本文将详细介绍Java枚举类实现key-value映射的多种方式,有需要的小伙伴可以根据需要... 目录前言一、基础实现方式1.1 为枚举添加属性和构造方法二、http://www.cppcns.co

Elasticsearch 在 Java 中的使用教程

《Elasticsearch在Java中的使用教程》Elasticsearch是一个分布式搜索和分析引擎,基于ApacheLucene构建,能够实现实时数据的存储、搜索、和分析,它广泛应用于全文... 目录1. Elasticsearch 简介2. 环境准备2.1 安装 Elasticsearch2.2 J

Java中的String.valueOf()和toString()方法区别小结

《Java中的String.valueOf()和toString()方法区别小结》字符串操作是开发者日常编程任务中不可或缺的一部分,转换为字符串是一种常见需求,其中最常见的就是String.value... 目录String.valueOf()方法方法定义方法实现使用示例使用场景toString()方法方法

Java中List的contains()方法的使用小结

《Java中List的contains()方法的使用小结》List的contains()方法用于检查列表中是否包含指定的元素,借助equals()方法进行判断,下面就来介绍Java中List的c... 目录详细展开1. 方法签名2. 工作原理3. 使用示例4. 注意事项总结结论:List 的 contain

Java实现文件图片的预览和下载功能

《Java实现文件图片的预览和下载功能》这篇文章主要为大家详细介绍了如何使用Java实现文件图片的预览和下载功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... Java实现文件(图片)的预览和下载 @ApiOperation("访问文件") @GetMapping("