如何在不修改原有模型的前提下实现嵌套对象的Builder构建器
实现方案
完全不需要修改原有实体类,只需要为每个层级的实体独立实现无侵入的Builder类即可,核心逻辑是父层级Builder的嵌套配置方法接收子Builder的配置委托,内部完成子实体的构建和赋值。
完整实现代码
// 最底层Contact对应的Builder public class ContactBuilder { private readonly Contact _contact = new Contact(); public ContactBuilder WithPhoneNo(string phoneNo) { _contact.PhoneNo = phoneNo; return this; } public Contact Build() => _contact; } // Address对应的Builder public class AddressBuilder { private readonly Address _address = new Address(); public AddressBuilder WithStreet(string street) { _address.Street = street; return this; } public AddressBuilder WithContact(Action<ContactBuilder> configure) { var contactBuilder = new ContactBuilder(); configure(contactBuilder); _address.Contact = contactBuilder.Build(); return this; } public Address Build() => _address; } // Owner对应的Builder public class OwnerBuilder { private readonly Owner _owner = new Owner(); public OwnerBuilder WithName(string name) { _owner.Name = name; return this; } public OwnerBuilder WithAddress(Action<AddressBuilder> configure) { var addressBuilder = new AddressBuilder(); configure(addressBuilder); _owner.Address = addressBuilder.Build(); return this; } public Owner Build() => _owner; } // 最顶层Advertisment对应的Builder public class AdBuilder { private readonly Advertisment _ad = new Advertisment(); public AdBuilder WithId(string id) { _ad.AdvertismentId = id; return this; } public AdBuilder WithOwner(Action<OwnerBuilder> configure) { var ownerBuilder = new OwnerBuilder(); configure(ownerBuilder); _ad.Owner = ownerBuilder.Build(); return this; } public Advertisment Build() => _ad; }
使用方式
注意你示例中把WithContact放在WithOwner下的写法不符合实体层级关系,正确写法应该把Contact配置放在Address的配置委托内,和实体的嵌套结构保持一致,最终调用效果如下:
var ad = new AdBuilder() .WithId("123") .WithOwner(ownerBuilder => ownerBuilder.WithName("NameOfOwner") .WithAddress(addressBuilder => addressBuilder.WithStreet("SomeStreet") .WithContact(contactBuilder => contactBuilder.WithPhoneNo("123-345-789")))) .Build();
优化建议
如果实体字段多、层级复杂,手写Builder重复工作量大,可以考虑用C#源生成器自动生成所有实体对应的Builder代码,因为你的实体是由JSON Schema统一生成的,每次更新Schema后只需要重新运行一次源生成器即可同步更新Builder,不需要手动维护代码。
内容的提问来源于stack exchange,提问作者tylkonachwile
相关产品推荐
相关产品推荐

