变化状态位于构建器模式的中心。有没有一种惯用的方式来实现F#中这样一个类的内部实现,它将减少/消除可变状态,同时保留通常的接口(该类将主要用于其他.NET语言)?在F#中实现构建器模式(a System.Text.StringBuilder)
这里有一个天真的实现:
type QueryBuilder<'T>() = //'
let where = ref None
let orderBy = ref None
let groupBy = ref None
member x.Where(cond) =
match !where with
| None -> where := Some(cond)
| _ -> invalidOp "Multiple WHERE clauses are not permitted"
// members OrderBy and GroupBy implemented similarly
一个想法是创建一个记录类型来存储的内部结构,并使用复制和更新表达式。
type private QueryBuilderSpec<'T> = //'
{ Where : ('T -> bool) option; //'
OrderBy : (('T -> obj) * bool) list; //'
GroupBy : ('T -> obj) list } //'
type QueryBuilder<'T>() = //'
let spec = ref None
member x.Where(cond) =
match !spec with
| None ->
spec := Some({ Where = Some(cond); OrderBy = []; GroupBy = [] })
| Some({ Where = None; OrderBy = _; GroupBy = _} as s) ->
spec := Some({ s with Where = Some(cond) })
| _ -> invalidOp "Multiple WHERE clauses are not permitted"
// members OrderBy and GroupBy implemented similarly
这一切似乎有点笨重,也许应该努力实现F#势在必行模式时,可以预期的。有没有更好的方法来做到这一点,再次,为了命令式语言而保留常用的构建器界面?
我并没有真正看到你的建设者之间有太大的区别。任何一个都可以从外部变化,而不管第一种还是第二种方式都没有实现。 –
没错。我没有看到消除可变状态的任何方法。不同之处在于第一个实现可以包含任意数量的可变变量。第二个实现有一个。是的,也许这是一个微不足道的区别。我讨厌这两个,但这是我需要建立的。我更喜欢F#,但也许我需要回到C#来做到这一点。只是以为在放弃F#之前我会得到更多的意见。 – Daniel