[英]F# Command Pattern
我正在嘗試實現命令模式來控制機器人。 我正在使用它來探索如何在 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
為了提出一個功能解決方案,我選擇讓機器人的動作在每次調用后在其新的 position 處返回一個機器人的新實例(避免突變)。 我還關閉了執行操作所需的 state 的命令功能。
我很好奇人們在實現該模式時是否認為這些是好的設計決策? 或者,如果人們可以就實施該模式提供任何其他建議?
為了避免采用 OO 方式將數據與“類型”中的操作組合並將這種組合表示為“對象”,我的 POV 中更實用的方法是在模塊中分別定義數據和操作,如下所示:
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 並使用 |> function 將其傳遞給一系列轉換 Walle“數據”的函數。 這完全是關於數據和該數據的轉換,沒有對象:)。 它可能不像命令模式,因為它更適合 OO 風格。 您真的不需要 FP 中的模式,還是我們?
對於機器人示例,我寧願只使用命令式樣式,即更改機器人 object 的狀態。 因為機器人 object 通常有狀態的概念和改變狀態的動作。 從OO設計的角度來看,有些對象最好是不可變的,例如.NET中的String、DateTime,但很多都不是。
不可變對象當然有優勢。 在您問題的持久版本中,您可以保存機器人的所有過去狀態,並且可以輕松地UnDo
機器人上的命令。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.