Шаблон команд F # - PullRequest
4 голосов
/ 05 мая 2011

Я пытаюсь реализовать шаблон команды для управления роботом.Я использую это, чтобы изучить, как реализовать шаблон команды в 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 ]

11 голосов
/ 05 мая 2011

Чтобы не использовать 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 и использовать функцию |> для передачи этого в ряд функций, которые преобразуют «данные» Walle.Это все о данных и преобразовании этих данных, никаких объектов :).Возможно, это не похоже на шаблон команды, так как он больше подходит для стиля OO.Вам действительно не нужны шаблоны в FP или мы?

1 голос
/ 05 мая 2011

Для примера с роботом я бы предпочел просто использовать императивный стиль, то есть изменение состояний объекта робота. Потому что у объекта-робота обычно есть понятие состояний и действий по изменению состояний. С точки зрения ОО-проектирования некоторые виды объектов лучше быть неизменяемыми, например, String, DateTime в .NET, но многие из них таковыми не являются.

Неизменные объекты, конечно, имеют свои преимущества. В постоянной версии в вашем вопросе вы можете сохранить все прошлые состояния робота и легко UnDo команды на робота.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...