设计模式之建造者模式

news/2024/10/17 22:18:36/

1、什么是建造者模式

建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。

2、代码演示

主机类:

public class Host {private String CPU;//CPU型号private String Memory;//内存条型号private String disk;//磁盘型号public String getCPU() {return CPU;}public Host(){}public Host(Host host){this.CPU=host.CPU;this.Memory=host.Memory;this.disk=host.disk;}public void setCPU(String CPU) {this.CPU = CPU;}public String getMemory() {return Memory;}public void setMemory(String memory) {Memory = memory;}public String getDisk() {return disk;}public void setDisk(String disk) {this.disk = disk;}
}

 建造者抽象类:

public abstract class Builder {//建造者抽象类public Host host=new Host();public Builder(){host=new Host();}public abstract void buildCPU();public abstract void buildDisk();public abstract void buildMemory();public Host build(){buildCPU();buildDisk();buildMemory();return new Host(host);}
}

联想建造者类:

public class LenovoBuilder extends Builder {@Overridepublic void buildCPU() {host.setCPU("联想CPU");}@Overridepublic void buildDisk() {host.setDisk("联想磁盘");}@Overridepublic void buildMemory() {host.setMemory("联想内存");}
}

苹果建造者类:

public class AppleBuilder extends Builder {@Overridepublic void buildCPU() {host.setCPU("苹果CPU");}@Overridepublic void buildDisk() {host.setDisk("苹果磁盘");}@Overridepublic void buildMemory() {host.setMemory("苹果内存");}
}

可见,如果我们想获取一个联想的主机,那么我们直接调用它的建造者类的build方法即可:

public class Test {public static void main(String[] args) {Builder builder=new LenovoBuilder();Host build = builder.build(); //直接获取联想的主机System.out.println("内存为:"+build.getMemory());System.out.println("CPU为:"+build.getCPU());System.out.println("硬盘为:"+build.getDisk());}
}

运行结果如下:

 可见,我们通过建造者类可以直接获取相关对象,而不用去关心它内部是如何实现的。

3、优缺点

优点:

①建造者模式的封装性很好。使用建造者模式可以有效的封装变化,在使用建造者模式的场景中,一般产品类和建造者类是比较稳定的,因此,将主要的业务逻辑封装在指挥者类中对整体而言可以取得比较好的稳定性。
②在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
③可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
④建造者模式很容易进行扩展。如果有新的需求,通过实现一个新的建造者类就可以完成,基本上不用修改之前已经测试通过的代码,因此也就不会对原有功能引入风险。符合开闭原则。

缺点:

造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。

4、模式扩展

大家可以看到,对于我们上述的建造者模式,比较简单单一,通常适用于要一个对象所有配件都来自于同一个厂家(同一个builder),因此,如果我们想组合那种混合的电脑,比如:CPU我觉得苹果好,想用苹果的CPU;内存我觉得三星的好,想用三星的内存;硬盘我觉得联想的好,想用联想的硬盘。那这种建造模式应该怎么实现呢?以下我们提供一种实现思路:

Host类:

public class Host {private String CPU;//CPU型号private String Memory;//内存条型号private String disk;//磁盘型号public Host(Builder builder){this.CPU=builder.CPU;this.Memory=builder.Memory;this.disk=builder.disk;}public static class Builder{private String CPU;//CPU型号private String Memory;//内存条型号private String disk;//磁盘型号public Builder setCPU(String CPU){this.CPU=CPU;return this;}public Builder setMemory(String memory){this.Memory=memory;return this;}public Builder setDisk(String disk){this.disk=disk;return this;}public Host build(){return new Host(this);}}@Overridepublic String toString() {return "Host{" +"CPU='" + CPU + '\'' +", Memory='" + Memory + '\'' +", disk='" + disk + '\'' +'}';}
}

测试类:

public class Test {public static void main(String[] args) {Host build = new Host.Builder().setDisk("联想Disk").setCPU("苹果CPU").setMemory("三星Memory").build();System.out.println("电脑配置如下:");System.out.println(build.toString());}
}

运行结果如下:

大家可以发现,上述代码风格是不是很像大家之前接触一些框架提供的“Builder”,没错,那些框架的实现其实也是这种思路。

5、模式对比

大家可能会发现,诶,这种模式和工厂模式有啥区别呢?

5.1 工厂方法模式VS建造者模式

工厂方法模式注重的是整体对象的创建方式;而建造者模式注重的是部件构建的过程,意在通过一步一步地精确构造创建出一个复杂的对象。
我们举个简单例子来说明两者的差异,如要制造一个超人,如果使用工厂方法模式,直接产生出来的就是一个力大无穷、能够飞翔、内裤外穿的超人;而如果使用建造者模式,则需要组装手、头、脚、躯干等部分,然后再把内裤外穿,于是一个超人就诞生了。

5.2 抽象工厂模式VS建造者模式

抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品:具有不同分类维度的产品组合,采用抽象工厂模式则是不需要关心构建过程,只关心什么产品由什么工厂生产即可。
建造者模式则是要求按照指定的蓝图建造产品,它的主要目的是通过组装零配件而产生一个新产品。

如果将抽象工厂模式看成汽车配件生产工厂,生产一个产品族的产品,那么建造者模式就是一个汽车组装工厂,通过对部件的组装可以返回一辆完整的汽车。


http://www.ppmy.cn/news/55577.html

相关文章

OpenCV——概率霍夫检测

概率霍夫变换是一种基于泛洪算法的直线检测算法。相较于传统霍夫变换&#xff0c;概率霍夫变换可以在保证一定的精度前提下&#xff0c;大大提高了直线检测效率。下面是 OpenCV C 实现概率霍夫检测的示例代码&#xff1a; #include <opencv2/opencv.hpp> #include &l…

华为OD机试真题(Java),整数编码(100%通过+复盘思路)

一、题目描述 实现一个整数编码方法&#xff0c;使得待编码的数字越小&#xff0c;编码后所占用的字节数越小。 编码规则如下&#xff1a; 编码时7位一组&#xff0c;每个字节的低7位用于存储待编码数字的补码&#xff1b;字节的最高位表示后续是否还有字节&#xff0c;置1表…

《利用光体积描记图信号的模糊递推特性估计无袖带血压的级联卷积神经网络模型》阅读笔记

目录 一、论文摘要 二、论文十问 Q1&#xff1a;论文试图解决什么问题&#xff1f; Q2&#xff1a;这是否是一个新的问题&#xff1f; Q3&#xff1a;这篇文章要验证一个什么科学假设&#xff1f; Q4&#xff1a;有哪些相关研究&#xff1f;如何归类&#xff1f;谁是这一…

Java并发(三)----创建线程的三种方式及查看进程线程

一、直接使用 Thread // 创建线程对象 Thread t new Thread() {public void run() {// 要执行的任务} }; // 启动线程 t.start(); 例如&#xff1a; // 构造方法的参数是给线程指定名字&#xff0c;推荐 Thread t1 new Thread("t1") {Override// run 方法内实现…

QSqlQuery简单使用

QSqlQuery简单使用 1 执行一个查询2 浏览查询结果3 插入、更新和删除记录关键代码 Qt 程序获取程序所在路径、用户目录路径、临时文件夹等特殊路径的方法程序所在路径当前工作目录用户目录路径我的文档路径桌面路径程序数据存放路径临时文件路径 Qt中路径问题小结 原文链接&…

c语言文件读写

原理 C语言文件读写的原理是&#xff0c;先打开文件&#xff0c;然后使用fread或fwrite函数读取或写入文件内容。 文件打开的方式有两种&#xff1a; 以写入模式打开文件&#xff0c;使用fopen()函数以"w"作为第一个参数&#xff0c;如果文件不存在则创建文件&…

20230427配置cv1826的buildroot在串口免登录的方法二

20230427配置cv1826的buildroot在串口免登录的方法二 2023/4/27 16:46 进度&#xff1a;可以拿掉密码&#xff0c;但是无法拿掉用户名&#xff01; 1、 Z:\buildroot1\buildroot\configs\cvitek_cv182x_defconfig BR2_TOOLCHAIN_EXTERNAL_GCC_6y BR2_TOOL…

简记二分算法模板与代码案例:整数二分和浮点数二分

本文以 Java 语言实现&#xff0c;整理的代码模板适用于编程竞赛。对代码模板原理的讲解不多&#xff0c;主要记录一下如何使用。 目录 一、算法模板 &#xff08;1&#xff09;整数二分 &#xff08;2&#xff09;浮点数二分 二、例题 例题&#xff1a;acwing-789.数的范…