You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

建造者模式是否存在潜在设计缺陷?方法设计合理性疑问

建造者模式两个设计疑问解答

为什么要单独设计getResult()方法?

  • 核心目的是实现构建流程和最终产品的完全解耦。经典GoF建造者模式里,编排构建步骤的角色是Director(指挥者),它只负责按固定顺序调用各个buildPart()方法,从设计上就不需要知道最终构建出来的是什么产品。同样一套构建流程,换个具体建造者实现,就可能产出完全不同类型的对象:比如同样执行buildTitle、buildBody、buildFooter三个步骤,HTML建造者返回HTML字符串,PDF建造者返回二进制PDF对象,Markdown建造者返回md格式文本。Director不需要处理这些差异,最终拿结果的动作是客户端发起的,getResult()就是留给客户端获取最终产物的统一入口。
  • 其次是为了保证返回对象的完整性。复杂对象的构建是过程性的,中间状态的半成品大多是不可用的:比如造车只装了轮子没装发动机、做报表只填了表头没填数据,这些状态的对象如果暴露出去很容易引发业务问题。getResult()可以在返回前做统一的合法性校验、资源初始化,确保交到客户端手里的一定是状态合法、可直接使用的完整对象。

为什么buildPart()方法没有返回值?这是不是冗余设计?

你觉得设计冗余,本质上是默认了“谁调用buildPart()谁就要拿结果”,但经典模式里调用buildPart()的是Director,它从职责划分上就不该拿到构建结果:

  • buildPart()的单一职责是修改建造者内部维护的产品实例状态,不需要对外暴露任何中间数据。如果给buildPart()加返回值,不管是返回建造者自身还是返回零件/半成品,都会强迫Director感知产品的内部结构:比如造车的建造者buildWheel()返回轮子对象,造房子的建造者buildWall()返回墙壁对象,那Director的流程代码就得针对不同产品做适配,彻底违背了“同一构建流程可复用生成不同产品”的核心设计目标。
  • 所谓“让buildPart()直接返回构建结果更高效”,其实是把经典建造者模式和现在常用的流式建造者变体搞混了。日常开发里我们经常写的链式调用Builder(比如builder.setName("a").setAge(1).build()),是没有独立Director的场景下的简化实现:客户端自己充当Director编排构建步骤,这时候让构建方法返回建造者自身确实写起来更顺畅,但这只是特定场景下的优化,不是普适的设计准则。如果你的场景需要复用统一构建流程、支持多类型产品构建,无返回值的buildPart()反而是耦合最低的设计。

可以参考最基础的经典实现伪代码,直观看到各角色的职责划分:

// 抽象建造者:定义统一构建步骤,不绑定具体产品
abstract class Builder {
    public abstract void buildPartA();
    public abstract void buildPartB();
    public abstract Object getResult();
}

// 具体建造者:自己维护内部产品实例,构建方法仅修改内部状态
class ConcreteBuilderA extends Builder {
    private ProductA product = new ProductA();
    @Override
    public void buildPartA() {
        product.setFeatureA("A类产品的A部分");
    }
    @Override
    public void buildPartB() {
        product.setFeatureB("A类产品的B部分");
    }
    @Override
    public ProductA getResult() {
        product.checkValid(); // 最终合法性校验
        return product;
    }
}

// 指挥者:只负责按顺序调用构建步骤,完全不接触具体产品实现
class Director {
    public void build(Builder builder) {
        builder.buildPartA();
        builder.buildPartB();
    }
}

// 客户端调用
public class Client {
    public static void main(String[] args) {
        Builder builder = new ConcreteBuilderA();
        Director director = new Director();
        director.build(builder);
        ProductA res = (ProductA) builder.getResult();
    }
}

从代码里就能看出来,Director的build方法完全不需要返回值,它的职责就是把流程跑完,拿结果是客户端的事,不存在“不拿结果为什么调用buildPart”的问题——调用buildPart本来就不是为了拿即时结果,是为了推进构建流程,最终结果本来就是等全流程跑完之后才需要获取的。


内容的提问来源于stack exchange,提问作者RedFox

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 05:09:20