F#命令模式

4

我正在尝试使用命令模式来控制机器人。我正在使用这个来探索如何在F#中实现命令模式。下面是我的实现:

type Walle(position, rotate) =     
    let (x:float,y:float) = position
    let rotation = rotate
    member this.Move(distance) =
        let x2 = distance * sin (System.Math.PI/180.0 * rotation)
        let y2 = distance * cos (System.Math.PI/180.0 * rotation)
        let newPosition = (x+x2, y+y2)
        Walle(newPosition, rotation)
    member this.Rotate(angle) = 
        let newRotation = 
            let nr = rotation + angle
            match nr with
            | n when n < 360.0 -> nr
            | _ -> nr - 360.0
        Walle(position, newRotation)

let Move distance = fun (w:Walle) -> w.Move(distance)
let Rotate degrees = fun (w:Walle) -> w.Rotate(degrees)

let remoteControl (commands:List<Walle->Walle>) robot = 
    commands |> List.fold(fun w c -> c w)

let testRobot() =
    let commands = [Move(10.0);Rotate(90.0);Move(16.0);Rotate(90.0);Move(5.0)]
    let init = Walle((0.0,0.0),0.0)
    remoteControl commands init

为了提供一个可用的解决方案,我选择让机器人的动作在每次调用后返回一个新的机器人实例(避免突变)。同时,我也让命令函数包含执行这些动作所需的状态。
我想知道在实现这种模式时,人们是否认为这些是好的设计决策?或者,是否有其他建议可以提供?
2个回答

12
为了避免走上将数据与操作结合为“类型”,并将此组合表示为“对象”的面向对象方法,我认为更加函数式的方法是在一个模块中分别定义数据和操作,如下所示:
module Walle = 
 type Walle = {Position : float * float; Rotation : float}

 let Move distance (w:Walle) = 
    let x2 = distance * sin (System.Math.PI/180.0 * w.Rotation)        
    let y2 = distance * cos (System.Math.PI/180.0 * w.Rotation)
    {w with Position = (w.Position |> fst) + x2, (w.Position |> snd) + y2 }

 let Rotate angle (w:Walle) = 
    let newRotation = 
        let nr = w.Rotation + angle
        match nr with
        | n when n < 360.0 -> nr
        | _ -> nr - 360.0
    {w with Rotation = newRotation}

现在你可以创建一个新的Walle并使用|>函数将其传递给一系列转换Walle"数据"的函数。这完全是关于数据和对数据的转换,没有对象 :). 虽然这可能不感觉像命令模式,因为那更适合面向对象的风格。但在FP中,你真的不需要模式,或者我们需要吗?


1
在机器人示例中,我更愿意使用命令式风格,即改变机器人对象的状态。因为机器人对象通常具有状态和更改状态的操作。从面向对象设计的角度来看,某些类型的对象更适合是不可变的,例如.NET中的String、DateTime,但很多对象并非如此。
当然,不可变的对象有优点。在您的问题中,可以保存机器人的所有过去状态,并可以轻松地使用UnDo命令对机器人进行撤消。

我能理解你希望Walle是可变的。 - David Dickson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接