创建型模式:建造者模式

news/2025/3/22 2:09:21

文章首发:
创建型模式:建造者模式

景

五大创建型模式之四:建造者模式。

简介

姓名 :建造者模式

英文名 :Builder Pattern

价值观 :专治丢三落四

个人介绍

Separate the construction of a complex object from its representation so that the same construction process can create different representations.
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
(来自《设计模式之禅》)

今天给大家介绍的是建造者模式。建造者模式的使用场景是:创建复杂的对象。什么才能算复杂对象?如果一个对象只需要通过 new XXX() 的方式创建,那就算是一个简单对象;如果需要 new XXX(),并且还要设置很多属性,那这种就可以称为复杂对象了,因为它的构建过程比较复杂。采用建造者模式,可以把这个复杂的构建过程抽离开,使它不依赖创建者。下面我们通过故事来讲解。

你要的故事

还记得小时候刚开始学煮汤,不了解怎么煮,第一次是煮了板栗排骨汤,因为板栗比较难熟,所以是跟排骨一起下锅,然后煮了 40 分钟,加了盐就可以出锅啦。第二次煮了冬瓜排骨汤,不懂得冬瓜容易熟,就和排骨一起下锅,煮了也差不多 40 分钟,下了盐和香菜,发现怎么这汤有点浓,冬瓜咋都不见了(全都煮透了),我妈看到这锅汤,才跟我说冬瓜容易熟,得先熬排骨,再放冬瓜进去煮。那时才发现熬汤特么还有这差异。

上面是背景哈,接下来我们来实现这个煲汤过程,冬瓜排骨汤是先加排骨,熬制 30 分钟,加冬瓜,熬制 18 分钟,加盐加香菜;板栗排骨汤是先加排骨和板栗,熬制 40 分钟,再加盐。这汤都需要加肉、加菜、熬制、加配料。我们使用下面代码实现这个煲冬瓜排骨汤和板栗排骨汤的过程。

public class NoBuilderTest {public static void main(String[] args) {// 熬制冬瓜排骨汤DongGuaPaiGuSoup dongGuaPaiGuSoup = new DongGuaPaiGuSoup();// 加排骨dongGuaPaiGuSoup.addMeat();// 熬制 30 分钟dongGuaPaiGuSoup.waitMinute(30);// 加冬瓜dongGuaPaiGuSoup.addVegetables();// 熬制 10 分钟dongGuaPaiGuSoup.waitMinute(10);// 加盐加香菜dongGuaPaiGuSoup.addIngredients();// 熬制板栗排骨汤BanLiPaiGuSoup banLiPaiGuSoup = new BanLiPaiGuSoup();// 加排骨banLiPaiGuSoup.addMeat();// 加板栗banLiPaiGuSoup.addVegetables();// 熬制 40 分钟banLiPaiGuSoup.waitMinute(40);// 加盐banLiPaiGuSoup.addIngredients();}}/*** 煲汤接口*/
interface Soup {/** 加肉 */void addMeat();/** 加菜 */void addVegetables();/** 熬制 */void waitMinute(int minute);/** 加配料 */void addIngredients();}/*** 冬瓜排骨汤*/
class DongGuaPaiGuSoup implements Soup {@Overridepublic void addMeat() {System.out.println("加排骨");}@Overridepublic void addVegetables() {System.out.println("加冬瓜");}@Overridepublic void waitMinute(int minute) {System.out.println("熬制 " + minute + " 分钟");}@Overridepublic void addIngredients() {System.out.println("加盐、加香菜");}
}/*** 板栗排骨汤*/
class BanLiPaiGuSoup implements Soup {@Overridepublic void addMeat() {System.out.println("加排骨");}@Overridepublic void addVegetables() {System.out.println("加板栗");}@Overridepublic void waitMinute(int minute) {System.out.println("熬制 " + minute + " 分钟");}@Overridepublic void addIngredients() {System.out.println("加盐");}
}

上面代码简单实现了煲冬瓜排骨汤和板栗排骨汤。煲汤我们要关注的点是:各操作的顺序,是先加肉先煮再加菜,还是肉和菜一起放进锅煮。上面代码中,这个过程是谁控制的?是煲汤的人,所以顺序由煲汤的人决定,甚至有可能忘记放配料啥的,这样子的汤就味道不够好。那怎么去解决这些问题?

我们通过建造者模式可以解决上面的 2 个问题:煲汤顺序问题和忘记加配料这种丢三落四行为。我们将这个煲汤顺序从煲汤者分离开来,让煲汤者只需要决定煲什么汤就好,让建造者来保证煲汤顺序问题和防止漏加配料。

我们用一个 SoupBuilder 来规范化煲汤过程,方法 buildSoup 给实现者提供一个设置煲汤顺序的地方。因为冬瓜排骨汤和板栗排骨汤熬制的过程不一样,所以分别用 DongGuaPaiGuSoupBuilder 和 BanLiPaiGuSoupBuilder 来具体实现冬瓜排骨汤和板栗排骨汤的熬制过程,也就是消除熬制过程和煲汤者的依赖关系。 Director 则相当于一个菜单,提供为熬汤者来选择熬什么汤。具体代码如下所示。

public class BuilderTest {public static void main(String[] args) {Director director = new Director();// 熬制冬瓜排骨汤director.buildDongGuaPaiGuSoup();// 熬制板栗排骨汤director.buildBanLiPaiGuSoup();}}/*** 煲汤建造接口*/
interface SoupBuilder {void buildSoup();Soup getSoup();
}/*** 冬瓜排骨汤建造者*/
class DongGuaPaiGuSoupBuilder implements SoupBuilder {private DongGuaPaiGuSoup dongGuaPaiGuSoup = new DongGuaPaiGuSoup();@Overridepublic void buildSoup() {// 加排骨dongGuaPaiGuSoup.addMeat();// 熬制 30 分钟dongGuaPaiGuSoup.waitMinute(30);// 加冬瓜dongGuaPaiGuSoup.addVegetables();// 熬制 10 分钟dongGuaPaiGuSoup.waitMinute(10);// 加盐加香菜dongGuaPaiGuSoup.addIngredients();}@Overridepublic Soup getSoup() {return dongGuaPaiGuSoup;}
}/*** 板栗排骨汤建造者*/
class BanLiPaiGuSoupBuilder implements SoupBuilder {BanLiPaiGuSoup banLiPaiGuSoup = new BanLiPaiGuSoup();@Overridepublic void buildSoup() {// 加排骨banLiPaiGuSoup.addMeat();// 加板栗banLiPaiGuSoup.addVegetables();// 熬制 40 分钟banLiPaiGuSoup.waitMinute(40);// 加盐banLiPaiGuSoup.addIngredients();}@Overridepublic Soup getSoup() {return banLiPaiGuSoup;}
}/*** 生产方*/
class Director {private DongGuaPaiGuSoupBuilder dongGuaPaiGuSoupBuilder = new DongGuaPaiGuSoupBuilder();private BanLiPaiGuSoupBuilder banLiPaiGuSoupBuilder = new BanLiPaiGuSoupBuilder();/*** 熬制冬瓜排骨汤*/public DongGuaPaiGuSoup buildDongGuaPaiGuSoup() {dongGuaPaiGuSoupBuilder.buildSoup();return (DongGuaPaiGuSoup) dongGuaPaiGuSoupBuilder.getSoup();}/*** 熬制板栗排骨汤*/public BanLiPaiGuSoup buildBanLiPaiGuSoup() {banLiPaiGuSoupBuilder.buildSoup();return (BanLiPaiGuSoup) banLiPaiGuSoupBuilder.getSoup();}}

通过用建造者实现,是不是保证了熬制汤的顺序并且一定会加够料?感受一下其中的奥秘吧。

代码:
Builder Pattern

总结

通过建造者模式,可以把本来强依赖的东西解绑,不仅仅解决依赖问题,还提高了封装性,让使用者不用明白内部的细节,用上面的例子说就熬汤不用关心怎么熬制的过程,就像我们想喝冬瓜排骨汤,告诉妈妈,妈妈熬制,我们并不知道是怎么熬制的。

推荐阅读

单一职责原则(方法:修改名字还是密码?接口:洗碗、买菜还是倒垃圾?类:注册、登录和注销)
里氏替换原则(我儿来自新东方烹饪)
依赖倒置原则(抠门的饭店老板)
接口隔离原则(小伙子的作坊)
迪米特法则(手机上看电子书)
开闭原则(社保这点事)
创建型模式:单例模式(小明就只有 1 辆车)
创建型模式:工厂方法(小明家的车库)
创建型模式:抽象工厂(宝马车就得用宝马轮胎和宝马方向盘)

设计模式文章会持续更新,欢迎关注公众号,第一时间获取文章推送。

公众号后台回复『大礼包』获取 Java、Python、IOS 等教程
加个人微信备注『教程』获取架构师、机器学习等教程

LieBrother

转载于:https://blog.51cto.com/7665794/2381117


https://dhexx.cn/news/show-1646350.html

相关文章

ChatGPT 指令大全

写报告 报告开头 模版 我现在正在 报告的情境与目的 。 我的简报主题是 主题,请提供 数字 种开头方式,要简单到 目标族群 能听懂,同时要足够能吸引人,让他们愿意专心听下去 示例 👉 我现在正在修台大的简报课&…

sniffer por经典案例分析

很经典的东西..网络管理员必备...很详细的..感觉好的话留下脚印..转载于:https://blog.51cto.com/450956/119501

从Vue.js谈谈前端开发的技术栈演变

2019独角兽企业重金招聘Python工程师标准>>> Vue 小结 本次串讲的主要目的在于给我们移动端的同学揭秘下目前前端开发的现状,和一些典型框架或者说是库的产生背景、以及设计思想和解决了什么样的问题。以 Vue.js 为例。此次讲解围绕以下几个方面展开&…

Number String(HDU 4055,动态规划递推,前缀和优化)

点击加号查看代码#include<bits/stdc.h>//前缀和优化版本,不易理解 using namespace std; #define ll long long const ll maxn1100; const ll mod1000000007; ll sum[maxn][maxn]; ll dp[maxn][maxn]; char str[maxn];int main() {str[0]*;str[1]*;scanf("%s"…

货物崇拜和货物崇拜编程

“货物崇拜编程”来源于“货物崇拜”这个词。 货物崇拜(英文&#xff1a;Cargo Cults&#xff0c;又译货物运动)是一种宗教形式&#xff0c;尤其出现于一些与世隔绝的落后土著之中。当货物崇拜者看见外来的先进科技物品&#xff0c;便会将之当作神祇般崇拜。美拉尼西亚盛行的一…

SQL-43 将所有to_date为9999-01-01的全部更新为NULL,且 from_date更新为2001-01-01。

题目描述 将所有to_date为9999-01-01的全部更新为NULL,且 from_date更新为2001-01-01。CREATE TABLE IF NOT EXISTS titles_test (id int(11) not null primary key,emp_no int(11) NOT NULL,title varchar(50) NOT NULL,from_date date NOT NULL,to_date date DEFAULT NULL);i…

bootstrap风格的multiselect插件——类似邮箱收件人样式

在开发颗粒云邮箱的过程中&#xff0c;遇到了一个前端的问题&#xff0c;就是邮箱收件人的那个multiselect的input输入框。不仅能够多选&#xff0c;还要能够支持ajax搜索&#xff0c;把联系人搜索出来。就是类似下面的这个东西&#xff1a; 网上找了很多类似的插件&#xff0c…

游戏编程入门手册

原文地址&#xff1a; http://www.gameres.com/Tutor/ 游戏制作新人&#xff1a; 用什么语言和编译器来做游戏&#xff1f; DirectX是什么&#xff1f; 学编程需要哪些书&#xff1f; 我怎样制作游戏&#xff1f; 哪些书是介绍游戏开发的&#xff1f; VC好还是C好&#xff1f;…

python安装教程(Windows系统,python3.7为例)

2019独角兽企业重金招聘Python工程师标准>>> python安装教程&#xff08;Windows系统,python3.7为例&#xff09; 2018年07月02日 20:33:56 duandian01 阅读数&#xff1a;27422 标签&#xff1a; pythonpython安装python入门 1. 在python的官网下载python对应版本&…

手机黑盒测试详细介绍

2019独角兽企业重金招聘Python工程师标准>>> 1、 Release Test Purpose: 测试手机的基本功能是否实现&#xff0c;是否有进一步测试的必要性 Attention: Release Test的Test Case具有一定的典型性&#xff0c;主要是反映手机最基本功能的Test Case 本类测试只需要依…