前言
以前最討厭設計複雜方法調用, 就是那種需要一堆有邏輯規則的 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; });
這個例子裏面有點複雜, 不適合用作教學, 看看調用自己揣摩一下就好.