前言
以前最讨厌设计复杂方法调用, 就是那种需要一堆有逻辑规则的 config 作为参数的方法.
这种 config 通常是一个大对象, 有许多 property, property 之间有存在一些逻辑, 比如当 property A 是什么的时候 B 必须也是什么.
如果单侧不管它, 那么调用方法的人就会很幸苦, 一直到 runtime 才会报错.
Fluent Builder 模式
Fluent Builder 模式就是用来有条有理的创建复杂对象的. 比如上面说到的 config.
很多地方都可以看到它的影子.
EF Core 和 OData 都用了这个方式来创建 model.
fluentvalidation 也是用了这个方式来创建 validation rules
如何实现
其内部原理就是通过几个小的 builder, 每一个 builder 负责一部分创建. 然后串起来.
每一个小 builder 就可以通过方法, 去声明类型, 和限制调用顺序等.
虽然它不能 100% 解决使用者调用错误的问题, 但是已经非常多了.
在设计方法调用的时候, 我们不可以认为使用者是开发人员就顺便的做, 应该要尽可能让调用简单, 智能, 有类型推到.
before
builder.HasPrincipalProperty(e => e.ProductName, e => e.Color.Product.Name, conditionalInfo: new RedundancyExpressionVersionConditionalInfo<Size> { WhereExpression = e => e.Type == SizeType.TypeA, WhenNoInCondition = WhenNoInCondition.AutomaticallySetToNull }); builder.HasPrincipalProperty(e => e.ProductId, e => e.Color.Product.Id, conditionalInfo: new RedundancyExpressionVersionConditionalInfo<Size> { WhereExpression = e => e.Type == SizeType.TypeA, WhenNoInCondition = WhenNoInCondition.AutomaticallySetToNull }); builder.HasPrincipalProperty(e => e.Age, e => e.Color.Product.Age, conditionalInfo: new RedundancyExpressionVersionConditionalInfo<Size> { WhereExpression = e => e.Type == SizeType.TypeA, WhenNoInCondition = WhenNoInCondition.AutomaticallySetToNull });
after
builder.HasPrincipalProperty() .Relation(e => e.Color.Product) .PropertyMap(e => e.ProductName, e => e.Name) .PropertyMap(e => e.ProductAge, e => e.Age) .PropertyMap(e => e.ProductId, e => e.Id) .Conditional(condition => { condition.WhereExpression = e => e.Type == SizeType.TypeA; condition.WhenNoInCondition = WhenNoInCondition.SetValueManually; });
这个例子里面有点复杂, 不适合用作教学, 看看调用自己揣摩一下就好.