【设计模式】第四篇:建造者模式也没那么难

BWH_Steven 2020-11-09 10:49:38
设计 模式 第四 第四篇 建造


一 引言

说明:如果想要直接阅读定义等理论内容,可以直接跳转到第二大点

在生活中有很多场景与我们今天要说的 “建造者模式” 是非常匹配的,打个比方一台计算机是由 CPU、内存、显卡、内存、鼠标、键盘、显示器等等内容组合而成的,我们想要一台电脑,我们不会可能自己去做这些配件,一般都是通过告诉销售公司,然后其派生产技术人员给你做好指定的配件。

先不管,谁买,谁做,谁管理的问题,我们可以分析得到,建造电脑的这个 “过程” 是稳定的也就是说,不管什么配置的电脑,这些配件都是必须要有的,只是具体的细节不一样,例如你的配置更好,他的差一些

但是,我作为一个买家,我并不想管这些,我只告诉你,我要一台中等配置的电脑,你负责“建造”好给我就行了,这就是建造者模式比较通俗的讲法

下面我们通过这个计算机的例子,循序渐进的看一下:

二 通过例子循序渐进认识建造者模式

首先,不管怎么建,怎么买,一个 Computer 电脑类是必须的,我们随便挑选三个组件来进行演示,CPU、内存、显示器,补充其 get set toString 方法

/**
* 产品:电脑
*/
public class Computer {
private String cpu; // CPU
private String graphicsCard; // 内存
private String displayScreen; // 显示器
public String getCpu() {
return cpu;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
public String getGraphicsCard() {
return graphicsCard;
}
public void setGraphicsCard(String graphicsCard) {
this.graphicsCard = graphicsCard;
}
public String getDisplayScreen() {
return displayScreen;
}
public void setDisplayScreen(String displayScreen) {
this.displayScreen = displayScreen;
}
@Override
public String toString() {
return "Computer{" +
"cpu='" + cpu + '\'' +
", graphicsCard='" + graphicsCard + '\'' +
", displayScreen='" + displayScreen + '\'' +
'}';
}
}

(一) 最简单直白的方式(不好)

这种方法基本可以说没什么技术含量了,直接 new + set 就行了

public class Test {
public static void main(String[] args) {
Computer computer = new Computer();
computer.setCpu("英特尔酷睿 i5 处理器");
computer.setGraphicsCard("4g内存");
computer.setDisplayScreen("14寸 1080p 60hz显示器");
System.out.println(computer.toString());
}
}

打印一下结果:

Computer{cpu='英特尔酷睿 i5 处理器', graphicsCard='4g', displayScreen='14寸 1080p 60hz显示器'}

(二) 客户直接联系生产技术人员

上面这种方式,不用说也知道不合适了,所以技术人员(建造者)他来了!但是不同的技术人员会制作的配件也不一样,例如有的会做 144hz 的显示器,而有的专攻 60hz 的显示器,有高低配置,不同型号之分

为此我们为其抽象出一个 ComputerBuilder 的抽象类

/**
* 电脑的建造者
*/
public abstract class ComputerBuilder {
abstract void buildCpu(); // 建造CPU
abstract void buildGraphicsCard(); // 建造内存
abstract void buildDisplayScreen(); // 建造显示器
abstract Computer getComputer(); // 拿到这台电脑
}

下面就来写建造者的具体实现,例如先写一个低配置电脑建造的实现

/**
* 低配置电脑
*/
public class LowConfigurationComputerBuilder extends ComputerBuilder {
private Computer computer;
public LowConfigurationComputerBuilder(){
computer = new Computer();
}
@Override
void buildCpu() {
computer.setCpu("英特尔酷睿 i5 处理器");
System.out.println("buildCpu: 英特尔酷睿 i5 处理器");
}
@Override
void buildGraphicsCard() {
computer.setGraphicsCard("8g内存");
System.out.println("buildGraphicsCard: 8g内存");
}
@Override
void buildDisplayScreen() {
computer.setDisplayScreen("1080p 60hz显示器");
System.out.println("buildDisplayScreen: 1080p 60hz显示器");
}
@Override
Computer getComputer() {
return computer;
}
}

测试一下:

public class Test {
public static void main(String[] args) {
// 创建低配置电脑建造者
LowConfigurationComputerBuilder builder = new LowConfigurationComputerBuilder();
builder.buildCpu();
builder.buildGraphicsCard();
builder.buildDisplayScreen();
Computer computer = builder.getComputer();
System.out.println("建造出的电脑: " + computer );
}
}

执行结果:

buildCpu: 英特尔酷睿 i5 处理器
buildGraphicsCard: 8g内存
buildDisplayScreen: 1080p 60hz显示器
建造出的电脑: Computer{cpu='英特尔酷睿 i5 处理器', graphicsCard='8g内存', displayScreen='1080p 60hz显示器'}

(三) 客户联系销售公司

虽然上面的方法是比第一种强一些,但是客户自己去联系生产技术人员,显然不是很合理,正常的做法,我们都是先去联系销售公司,告诉他们我想要什么配置的电脑就可以了,细节我并不想管

public class SalesCompany {
public Computer buildComputer(ComputerBuilder builder){
builder.buildCpu();
builder.buildGraphicsCard();
builder.buildDisplayScreen();
return builder.getComputer();
}
}

测试代码

public class Test {
public static void main(String[] args) {
// 创建低配置电脑建造者
LowConfigurationComputerBuilder builder = new LowConfigurationComputerBuilder();
// 创建电脑销售中心
SalesCompany salesCompany = new SalesCompany();
// 指定具体的电脑建造者去完成 电脑 这个产品
Computer computer = salesCompany.buildComputer(builder);
System.out.println("建造出的电脑: " + computer );
}
}

现在代码已经比较完善了,也就是我们买家通过联系电脑销售中心,然后销售中心去调用用户想要的配置的建造者,刚才我们创建的是一个“低配置电脑建造者”,如果我们想要换成中等配置的电脑,该怎么做呢?

现在只需要增加一个中等配置电脑建造者,实现Builder抽象类就可以了

/**
* 低配置电脑
*/
public class MiddleConfigurationComputerBuilder extends ComputerBuilder {
private Computer computer;
public MiddleConfigurationComputerBuilder(){
computer = new Computer();
}
@Override
void buildCpu() {
computer.setCpu("英特尔酷睿 i7 处理器");
System.out.println("buildCpu: 英特尔酷睿 i7 处理器");
}
@Override
void buildGraphicsCard() {
computer.setGraphicsCard("16g内存");
System.out.println("buildGraphicsCard: 16g内存");
}
@Override
void buildDisplayScreen() {
computer.setDisplayScreen("2k 144hz显示器");
System.out.println("buildDisplayScreen: 2k 60hz显示器");
}
@Override
Computer getComputer() {
return computer;
}
}

测试一下

public class Test {
public static void main(String[] args) {
MiddleConfigurationComputerBuilder builder = new MiddleConfigurationComputerBuilder();
// 创建电脑销售中心
SalesCompany salesCompany = new SalesCompany();
// 指定具体的电脑建造者去完成 电脑 这个产品
Computer computer = salesCompany.buildComputer(builder);
System.out.println("建造出的电脑: " + computer );
}
}

运行结果

buildCpu: 英特尔酷睿 i7 处理器
buildGraphicsCard: 16g内存
buildDisplayScreen: 2k 60hz显示器
建造出的电脑: Computer{cpu='英特尔酷睿 i7 处理器', graphicsCard='16g内存', displayScreen='2k 144hz显示器'}

其实到这里一个建造者模式的实例就写完了,下面我们结合概念,来深入理解一下建造者模式

三 建造者模式

(一) 概念

建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

  • 也就是说,产品的生成过程或者说组成,是不变的,而每一部分都是可以自行选择的,即其内部表象是可以变化的,这也就是所说的变与不变相分离

  • 此种情况下,用户只需要指定建造的类型就可以得到他们,而具体的过程和细节就不需要知道了

(二) 优缺点

首先,此模式封装性好,构建和表示进行了分离,每一个建造者都是相互独立的,利于解耦和扩展,符合 “开闭原则” 同时客户调用时,不需要知道产品细节

但是也正是因为产品生成过程这个不变的部分,限制了它的使用范围,同时如果产品内部日后发生什么改变,则建造者也得同样修改,维护成本不小

(三) 结构

根据上面的结构图,我们分别说明一下其中的四个角色(除 Client 调用者以外)

  • Product(产品角色):多个组件构成的复杂对象,即上述例子中的电脑
  • Builder(抽象建造者):一个包含创建产品各个子部件的抽象方法的接口/抽象类,一般还包含一个返回结果的方法,如上述中的 ComputerBuilder 类
  • ConcreteBuilder(具体建造者):Builder 的具体实现类,如上述中具体的 低配置电脑建造者 和 中等配置电脑建造者
  • Director(指挥者):调用建造者对象中的部件构造与装配方法,以创建一个复杂对象
    • 指挥者中不含具体产品信息
    • 其隔离了客户与对象的生产过程

(四) 适用场景

  • 顺序会对同一方法的结果产生影响,例如建房子,应当先打地基,再架钢筋水泥
  • 同一个对象可以装配不同的部件或者零件,同时结果不同
  • 产品类有复杂的内部结构,且这些产品对象具有共性
版权声明
本文为[BWH_Steven]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/ideal-20/p/13946868.html

  1. 【计算机网络 12(1),尚学堂马士兵Java视频教程
  2. 【程序猿历程,史上最全的Java面试题集锦在这里
  3. 【程序猿历程(1),Javaweb视频教程百度云
  4. Notes on MySQL 45 lectures (1-7)
  5. [computer network 12 (1), Shang Xuetang Ma soldier java video tutorial
  6. The most complete collection of Java interview questions in history is here
  7. [process of program ape (1), JavaWeb video tutorial, baidu cloud
  8. Notes on MySQL 45 lectures (1-7)
  9. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  10. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  11. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  12. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  13. 【递归,Java传智播客笔记
  14. [recursion, Java intelligence podcast notes
  15. [adhere to painting for 386 days] the beginning of spring of 24 solar terms
  16. K8S系列第八篇(Service、EndPoints以及高可用kubeadm部署)
  17. K8s Series Part 8 (service, endpoints and high availability kubeadm deployment)
  18. 【重识 HTML (3),350道Java面试真题分享
  19. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  20. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  21. [re recognize HTML (3) and share 350 real Java interview questions
  22. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  23. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  24. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  25. RPC 1: how to develop RPC framework from scratch
  26. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  27. RPC 1: how to develop RPC framework from scratch
  28. 一次性捋清楚吧,对乱糟糟的,Spring事务扩展机制
  29. 一文彻底弄懂如何选择抽象类还是接口,连续四年百度Java岗必问面试题
  30. Redis常用命令
  31. 一双拖鞋引发的血案,狂神说Java系列笔记
  32. 一、mysql基础安装
  33. 一位程序员的独白:尽管我一生坎坷,Java框架面试基础
  34. Clear it all at once. For the messy, spring transaction extension mechanism
  35. A thorough understanding of how to choose abstract classes or interfaces, baidu Java post must ask interview questions for four consecutive years
  36. Redis common commands
  37. A pair of slippers triggered the murder, crazy God said java series notes
  38. 1、 MySQL basic installation
  39. Monologue of a programmer: despite my ups and downs in my life, Java framework is the foundation of interview
  40. 【大厂面试】三面三问Spring循环依赖,请一定要把这篇看完(建议收藏)
  41. 一线互联网企业中,springboot入门项目
  42. 一篇文带你入门SSM框架Spring开发,帮你快速拿Offer
  43. 【面试资料】Java全集、微服务、大数据、数据结构与算法、机器学习知识最全总结,283页pdf
  44. 【leetcode刷题】24.数组中重复的数字——Java版
  45. 【leetcode刷题】23.对称二叉树——Java版
  46. 【leetcode刷题】22.二叉树的中序遍历——Java版
  47. 【leetcode刷题】21.三数之和——Java版
  48. 【leetcode刷题】20.最长回文子串——Java版
  49. 【leetcode刷题】19.回文链表——Java版
  50. 【leetcode刷题】18.反转链表——Java版
  51. 【leetcode刷题】17.相交链表——Java&python版
  52. 【leetcode刷题】16.环形链表——Java版
  53. 【leetcode刷题】15.汉明距离——Java版
  54. 【leetcode刷题】14.找到所有数组中消失的数字——Java版
  55. 【leetcode刷题】13.比特位计数——Java版
  56. oracle控制用户权限命令
  57. 三年Java开发,继阿里,鲁班二期Java架构师
  58. Oracle必须要启动的服务
  59. 万字长文!深入剖析HashMap,Java基础笔试题大全带答案
  60. 一问Kafka就心慌?我却凭着这份,图灵学院vip课程百度云