我正在重新设计一个库,我对当前的设计模式不满意。这个问题涉及将策略模式与State monad结合使用
我有一个Filter
. 在其基本实现中,它所做的只是获取一些类型的数据馈送'd
并更新自身,生成自身的新更新副本。
[<AbstractClass>]
type Filter<'d, 'F> (state: 'F) =
member val StateVariable = state with get
abstract member Update: 'd -> Filter<'d, 'F>
然后我有一个ISignalGenerator
,它需要一个过滤器、环境数据并对其进行处理以生成一个Signal
类型'S
。
type ISignalGenerator<'d, 'F, 'S> =
abstract member GenerateSignal: 'd -> Filter<'d,'F> -> 'S
是SignalGenerator
一个策略模式对象。在SignalGenerator
的实现中,库用户挂载将使用和组合以生成Signal
.
我可以将我的代码包装在一个状态 monad中。与一些环境变量(数据馈送)一起,状态单子将携带“过滤器”作为状态。SignalGenerator
然后将通过 state monad(类型的数据馈送'd
和Filter
) 获取状态更新
我的设计问题是我想将SignalGenerator
类型与工作流的开发分离,即我想避免将 state monad 嵌套在SignalGenerator
. 是否有功能设计模式来实现这一目标?
编辑
根据 Tomas 的评论,我制作了一个玩具模型。选择策略类是基于将许多函数包装在一起的需要。
/////////////////////////////////////////////////////////////////////////////////////
// Definition of the state
/////////////////////////////////////////////////////////////////////////////////////
type StateFunc<'State, 'T> = 'State -> 'T * 'State
/////////////////////////////////////////////////////////////////////////////////////
// Definition of the State monad type
/////////////////////////////////////////////////////////////////////////////////////
type StateMonadBuilder<'State>() =
// M<'T> -> M<'T>
member b.ReturnFrom a : StateFunc<'State, 'T> = a
// 'T -> M<'T>
member b.Return a : StateFunc<'State, 'T> = ( fun s -> a, s)
// M<'T> * ('T -> M<'U>) -> M<'U>
member b.Bind(p : StateFunc<_, 'T>, rest : 'T -> StateFunc<_,_>) : StateFunc<'State, 'U> =
(fun s ->
let a, s' = p s
rest a s')
// Getter for the whole state, this type signature is because it passes along the state & returns the state
member b.getState : StateFunc<'State, _> = (fun s -> s, s)
// Setter for the state
member b.putState (s:'State) : StateFunc<'State, _> = (fun _ -> (), s)
/////////////////////////////////////////////////////////////////////////////////////
// The actual example
/////////////////////////////////////////////////////////////////////////////////////
let state = StateMonadBuilder<int> ()
// DoubleFunctOne defines standard operations that remain always the same
type Strategy (functOne) =
member this.DoubleFunctOne (x: int) = state {
let! res = functOne x
return res * 2 }
// I introduce customization with the definition of this function.
// Whenever I need, I will swap the function with some other
let myFunctOne x = state {
let someOtherFun x = x + 10
let! currState = state.getState
return currState * someOtherFun x}
// Here I mount the custom function on the strategy class, so the Strategy.DoubleFunctOne can produce a result
// In order to do so, I need to keep the construction in the state monad
let strategy1 = state {
return Strategy (myFunctOne) }
// Here begins the client side. The client will consume the methods provided by my strategies.
// He should not be concerned by the construction of the strategies
// Ok, then, let's put our work in production
let test1 = (state {
let! strategy = strategy1
return! strategy.DoubleFunctOne 10 }) 9
我想知道是否会有一种模式解决方案,Strategy
该类可以使用已安装的功能,而无需将状态单子嵌套在其腹部。换句话说,有没有办法推迟 的定义let state = StateMonadBuilder<int> ()
,而不会陷入类型推断头痛?
我对函数式编程和 F# 比较陌生。请让我知道我的问题是否有意义!谢谢。