发布时间:2026-03-05
浏览次数:0
你的例句似乎不太完整或存在错误,不太能准确理解其确切意思从而进行改写。请提供完整且准确的句子。
把一个复杂对象的构建,跟它的表示分离开来,致使同样的构建过程,能够创造出不一样的表示。
—— GoF《设计模式》
从定制一台电脑说起
你走进一家电脑定制店,跟店员说:"我要一台电脑。"
店员向你询问,关于CPU的需求怎样,内存的大小是多少,硬盘选择SSD还是HDD,显卡是否需要独显,是否要添加水冷,机箱是什么颜色,电源的瓦数是多少。
你一脸懵——你只想买台电脑,为什么要回答这么多?
此刻变换成另一种感受,您讲出声“我渴望拥有一台用于打游戏的主机”,从事刷机工作之人便心领神会,协助您挑选好 i9,配备64G内存,选用RTX 4090,采用水冷散热方式,您无需知晓每一个部件,由专业的人士帮您依照步骤逐一进行组装。
构造函数的三条路,每条都是坑
伸缩构造函数
生成一个新的对象,其属性值依次为“i9”,“64G”,“2TB”,真,真,“黑色”,850,真。
第五个 true 代表什么?天知道。
处于这种状态的对象,在经历多次set操作期间,呈现出“不完整”的特性,而这种特性会导致多线程环境中潜藏危险,这种情况使其不可能被构造成为具备不可替代性的对象。
模式呈现为,链式调用,此过程针对每一个参数都赋予了名字,并且,是一次性构建,即在 build() 执行的时候,对象完全完整,同时,支持不可变特性,而且对于可选参数设定了有默认值的情况。真可谓是同时达成三个方面的完美状态。
GoF 经典结构
明确“怎么建”的步骤先后次序,知悉“建什么”的具体达成方式,针对相同的某个借助不同的,从而打造出各异的产品。
示例一:GoF 经典版 —— 电脑装机
Java · 接口
public interface ComputerBuilder {
void buildCpu();
void buildRam();
void buildStorage();
void buildGpu();
void buildCooling();
void buildPowerSupply();
Computer getResult();
}
Java · 游戏主机
public class GamingComputerBuilder implements ComputerBuilder {
private Computer computer = new Computer();
public void buildCpu() { computer.setCpu("Intel i9-14900K"); }
public void buildRam() { computer.setRam("64GB DDR5-6000"); }
public void buildStorage() { computer.setStorage("2TB NVMe Gen5"); }
public void buildGpu() { computer.setGpu("RTX 4090 24GB"); }
public void buildCooling() { computer.setCooling("360mm 水冷"); }
public void buildPowerSupply() { computer.setPowerSupply("1000W 金牌"); }
public Computer getResult() { return computer; }
}
Java ·
public class ComputerDirector {
private ComputerBuilder builder;
public ComputerDirector(ComputerBuilder builder) {
this.builder = builder;
}
// Director 控制构建顺序
public Computer construct() {
builder.buildCpu();
builder.buildRam();
builder.buildStorage();
builder.buildGpu();
builder.buildCooling();
builder.buildPowerSupply();
return builder.getResult();
}
}
输出
=== 游戏主机 ===
电脑配置 {
CPU: Intel i9-14900K
内存: 64GB DDR5-6000
存储: 2TB NVMe Gen5
显卡: RTX 4090 24GB
散热: 360mm 水冷
电源: 1000W 金牌
}
为一台 i5 加上集显的办公机生产制造,需置换成一个 r、同样的 () 完成。客户端没有必要清楚 i9 搭配何种主板。
示例二: Java 流式版 —— 定制一杯咖啡
在日常Java开发里,更为习见的是Bloch所推行的那种“流式”,其存在一种情形是没有codejock skin builder,要借由链式调用去化解参数爆炸的问题。
Java · + 内部
public class Coffee {
private final String size; // 必选
private final String baseType; // 必选
private final int extraShots; // 可选
private final String milk; // 可选
private final boolean whippedCream;
private final String syrup;
private final boolean iced;
private Coffee(Builder b) {
this.size = b.size;
this.baseType = b.baseType;
this.extraShots = b.extraShots;
this.milk = b.milk;
this.whippedCream = b.whippedCream;
this.syrup = b.syrup;
this.iced = b.iced;
}
public static class Builder {
private final String size;
private final String baseType;
private int extraShots = 0;
private String milk = null;
private boolean whippedCream = false;
private String syrup = null;
private boolean iced = false;
public Builder(String size, String base) {
this.size = size;
this.baseType = base;
}
public Builder extraShots(int n) { extraShots = n; return this; }
public Builder milk(String m) { milk = m; return this; }
public Builder whippedCream() { whippedCream = true; return this; }
public Builder syrup(String s) { syrup = s; return this; }
public Builder iced() { iced = true; return this; }
public Coffee build() { return new Coffee(this); }
}
}
使用——这就是 最迷人的地方
Java
// 一杯简单的冰美式
Coffee americano = new Coffee.Builder("Grande", "Espresso")
.iced()
.build();
// 一杯花里胡哨的定制咖啡
Coffee fancy = new Coffee.Builder("Venti", "ColdBrew")
.iced()
.extraShots(2)
.milk("燕麦奶")
.syrup("香草")
.whippedCream()
.build();
对比一下没有 的世界
伸缩构造函数
新建一个名为 \"Venti\" 的对象,其初始化相关内容为空字符串,数字为2,饮品为燕麦奶,布尔值为真,口味为香草,另一个布尔值为真。
第五个 true 是什么?
.(2).牛奶(“燕麦奶”).().糖浆(“香草”).加冰块()。
每个参数都有名字
并且,它是不可以改变的(所有的字段都是最终形式),具备线程安全的特性,在构建完成之后是不能够被篡改的。
两种 的对比
维度
GoF 经典版
Java 流式版
核心问题
同一过程创建不同表示
构造函数参数过多
位置
独立子类
产品的内部静态类
产品可变性
通常可变
通常不可变 (final)
日常使用频率
较少
极高(Java 主流写法)
典型场景
文档导出 PDF/HTML
配置对象、请求对象
JDK 和框架中的影子
— 最基础的 。() 链式构建,最后 () 返回成品。
. — 逐个 add(),最后 build() 生成 。
以下是改写后的:.关于新的相关内容,要进行这样的操作,先执行某操作,设置其链接到某个地址,再执行其他操作,涉及两个不同细节,然后通过这个方法发送具有特定内容的请求,最后构建完成。这可是后端必不可少的技能要点。
@ — 一个注解自动生成全套 代码。终极偷懒方案。
用还是不用?
适宜予以运用的情形包括:构造函数的参数数目超出了4个,特别是存在数量众多的可选参数。有需要使用不可变对象,然构建过程颇为复杂。在同一构建步骤里,要生成不同的产品表示形式。用以判断的标准为:当看到具有5个及以上参数的构造函数,或存在连续的调用——这便是一种信号。
不该运用:对象仅有两三个参数,直接采用构造函数就行。每一个产品类都需要一个与之对应的类,当结构简易的时候,这样的代价是不值得的。
你的内容似乎不完整且杂乱无意义,请提供完整且有意义的句子以便准确改写。
—— GoF
GoF着重强调(分离),构建的步骤具备着稳定性,而发生变动的乃是每一步骤的具体实现方式。这与模板方法有着异曲同工之处,只不过模板方法所分离的是“算法步骤”,而此处所分离的是“构建步骤”。
与其他模式的关系
对比抽象工厂,如下所示:抽象工厂所创建的是“一族产品”,它是分步去构建“一个复杂产品”的。其中,前者的产品特点是简单然而数量众多,后者的产品特点则是仅有一个但结构复杂。
通过流式接口,其中的流式,等于模式加上流式接口(该接口方法返回this),这两者在本质上天然地呈现互为补充的状态。
对比工厂方法:工厂方法直接达成对象创建,分阶段构建。运用工厂方法能一次性完成创建,若需要多个步骤且具备顺序则采用。
小结
建造者模式,属于创建型模式,是其中最为“务实”的那一个组成部分了,它所解决的是这样一个较为朴素的问题,即当对象变得极为复杂,并且所需参数数量过多的情况下,借助何种方式能够以一种优雅且恰当的姿态将其构造出来呢?
答案并非一股脑地往构造函数里塞,得是分着步骤,有选择性地去构建。就如同定制电脑之际,你只要说一句“我打算打游戏”——配置由那来搞定。
从GoF的codejock skin builder,加上,转变到Java的流式,而后又涉及,以及——此模式已然深深嵌入Java基因。
明日预告
建立型模式的最后一个,是原型模式,在创建对象成本高昂之际,怎样借由“克隆”去降低花费。
每天一个设计模式 · GoF × Java 实战系列
如有侵权请联系删除!
Copyright © 2023 江苏优软数字科技有限公司 All Rights Reserved.正版sublime text、Codejock、IntelliJ IDEA、sketch、Mestrenova、DNAstar服务提供商
13262879759
微信二维码