C# 建造者模式实现方法 C#如何使用Builder Pattern构建复杂对象

1次阅读

建造者模式在 C# 中通过类设计约定实现,核心是将构造逻辑移至 Builder 类并由 Build() 唯一出口完成终态校验与对象创建;Builder 需可变、链式调用(各方法返回 this),字段私有且仅 Builder 管理,校验和副作用统一在 Build() 中处理,Director 为可选流程封装组件。

C# 建造者模式实现方法 C# 如何使用 Builder Pattern 构建复杂对象

建造者模式在 C# 中不是靠语言特性强制实现的,而是通过类设计约定来达成——核心是把对象构造逻辑从客户端剥离,由 Builder 类逐步组装,再由 Director(可选)或直接由客户端触发 Build() 得到最终对象。

Builder 类必须是可变的、链式调用友好的

多数人一开始写错的地方,是让 Builder 方法返回 void 或新实例但不复用当前状态。正确做法是每个设置方法都返回 this,支持链式调用:

public class PizzaBuilder {private string _size = "medium";     private bool _hasCheese = true;     private List<string> _toppings = new(); <pre class="brush:php;toolbar:false;">public PizzaBuilder WithSize(string size) {_size = size; return this;} public PizzaBuilder WithCheese(bool has) {_hasCheese = has; return this;} public PizzaBuilder AddTopping(string topping) {_toppings.Add(topping); return this; }  public Pizza Build() => new(_size, _hasCheese, _toppings);

}

  • 所有字段必须是 private 且由 Builder 独占管理,避免外部绕过构造逻辑直接改状态
  • 不要在 WithXxx() 中做校验或副作用(如网络请求),那属于 Build() 阶段职责
  • 如果需要不可变性保障,Build() 后可将内部字段设为只读,或返回 readonly struct 封装

Build() 方法才是对象创建的唯一出口

真正关键的不是怎么“设参数”,而是谁、何时、以什么顺序“合成对象”。Build() 必须承担终态校验和对象实例化双重责任:

public Pizza Build() {     if (_toppings.Count == 0)         throw new InvalidOperationException("At least one topping is required."); <pre class="brush:php;toolbar:false;">// 防止重复构建 if (_isBuilt) throw new InvalidOperationException("Builder already used.");  _isBuilt = true; return new Pizza(_size, _hasCheese, _toppings.AsReadOnly());

}

  • 校验逻辑放在这里,而不是分散在每个 WithXxx() 中——否则易漏、难维护
  • _isBuilt 标志防止重复调用 Build(),避免状态污染或意外共享
  • 返回新对象时,尽量用只读集合(如 IReadOnlyList<t></t>)暴露内部数据,切断外部修改通路

Director 不是必需的,但适合固定流程复用

当多个地方都要按相同步骤构造对象(比如“标准素食披萨”“儿童套餐披萨”),可以抽一个 Director 封装流程,避免客户端重复写链式调用:

public class PizzaDirector {public Pizza MakeVegetarianPizza(PizzaBuilder builder) =>         builder.WithSize("large")                .WithCheese(true)                .AddTopping("mushrooms")                .AddTopping("bell peppers")                .AddTopping("olives")                .Build();}
  • Director 只依赖抽象 Builder(接口或基类),不绑定具体实现,便于扩展不同风格的构建器
  • 如果业务流程简单或变化频繁,跳过 Director 直接链式调用更轻量、更直观
  • 别为了模式而加 Director——它只是流程模板,不是建造者模式的必要组成部分

最常被忽略的一点:建造者模式的价值不在语法糖,而在把“构造契约”显式化。一旦 Build() 成为唯一合法出口,你就天然获得了构造过程的可观测性、可测试性和可拦截性——比如加日志、埋点、权限检查,全都可以在 Build() 入口统一处理,而不是散落在十几个构造函数或工厂方法里。

星耀云
版权声明:本站原创文章,由 星耀云 2026-03-19发表,共计1929字。
转载说明:转载本网站任何内容,请按照转载方式正确书写本站原文地址。本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。
text=ZqhQzanResources