
参数太多写成一坨建造者模式救不了你但能让你好过一点接手过一个老接口方法签名长成这样public Order createOrder(String userId, String productId, String address,String phone, String couponCode, String paymentType,String invoiceType, String invoiceTitle, String remark) {// ...}9 个参数全是 String调用的时候你根本分不清哪个是电话哪个是优惠券码。更要命的是后来又加了两个可选参数只好重载public Order createOrder(String userId, String productId, String address,String phone, String couponCode, String paymentType,String invoiceType, String invoiceTitle, String remark) { ... }public Order createOrder(String userId, String productId, String address,String phone, String couponCode, String paymentType,String invoiceType, String invoiceTitle, String remark,String deliveryTime, String giftMessage) { ... }参数再多两个调用方就得翻半天源码才能搞清楚每个位置该填什么。---建造者模式的做法把参数拆成一个个有意义的设置方法最后一步组装出对象public class OrderBuilder {private String userId;private String productId;private String address;private String phone;private String couponCode;private String paymentType;private String invoiceType;private String invoiceTitle;private String remark;private String deliveryTime;private String giftMessage;public OrderBuilder userId(String userId) {this.userId userId;return this;}public OrderBuilder productId(String productId) {this.productId productId;return this;}public OrderBuilder address(String address) {this.address address;return this;}public OrderBuilder phone(String phone) {this.phone phone;return this;}public OrderBuilder couponCode(String couponCode) {this.couponCode couponCode;return this;}// ... 其他 setterpublic Order build() {if (userId null || productId null) {throw new IllegalStateException(userId 和 productId 不能为空);}return new Order(userId, productId, address, phone,couponCode, paymentType, invoiceType,invoiceTitle, remark, deliveryTime, giftMessage);}}调用变成这样Order order new OrderBuilder().userId(U1001).productId(P2002).address(上海市浦东新区).phone(13800138000).couponCode(SAVE20).paymentType(WECHAT).build();每个参数有自己的方法名一目了然。参数有增减只改 Builder 类调用方不care。---Lombok 的 Builder实际开发中基本不会手写 BuilderLombok 一个注解搞定Builderpublic class Order {private String userId;private String productId;private String address;private String phone;private String couponCode;private String paymentType;private String invoiceType;private String invoiceTitle;private String remark;private String deliveryTime;private String giftMessage;}编译之后自动生成 Builder 内部类和链式方法用法跟手写的一模一样。但有坑。Builder默认生成全参构造器你的对象可能有些字段是必填的有些是可选的。默认情况下 Builder 不区分调用方可以只传 userId 就 build编译不会报错运行时才炸。解决方式是在 build 方法里做校验或者用自定义 Builder 指定必填参数放构造器里Builderpublic class Order {NonNull private final String userId;NonNull private final String productId;private String address;private String phone;// 可选字段用默认值Builder.Default private String paymentType ALIPAY;}NonNull会在构建时做 null 检查比运行时才发现要靠谱。---和工厂模式的区别经常有人搞混这两个模式因为都是创建对象的。- 工厂方法关注的是创建哪种对象——根据条件选不同实现- 建造者关注的是组装对象的细节——同一个类参数不同组装方式不同你有一个Payment接口有支付宝、微信两种实现选哪个是工厂方法的事。你有Order类9 个参数要填怎么填得舒服是建造者的事。两个模式解决的是不同维度的问题经常一起用——工厂负责创建建造者负责组装。---什么时候不该用参数少于 4 个直接用构造器或 setter 就够了。用 Builder 反而多了一层抽象代码更啰嗦。Builder 也不适合那种参数经常变动、结构不固定的对象。如果你的对象字段隔三差五加一个改一个Builder 也要跟着改并没有省多少事——这时候该反思的是你的领域模型设计而不是用什么创建方式。还有一个细节Builder 创建的对象通常应该是不可变的。build()返回的对象如果还能被修改那 Builder 的链式调用就失去了意义——调用方完全可以直接拿对象去改何必在构建阶段费劲设参数。BuilderGetterpublic class Order {private final String userId;private final String productId;private final String address;// 全部 final不可变}---我在做一个用卡皮巴拉讲 23 个设计模式的微信小程序「**爪爪代码冒险记**」漫画 答题闯关比翻书有意思。微信搜「爪爪代码冒险记」就能找到。