F# - 工厂方法设计模式

时间:2011-04-14 11:49:02

标签: design-patterns f#

下面是我尝试使用F#实现工厂方法设计模式,同时尝试使其更加功能(即不是直接的OO实现)。以下是我提出的建议:

type ISkateBoard = abstract Model : unit -> string

type SkateBoard = 
| Roskopp 
| Peters
    interface ISkateBoard
        with member this.Model() = 
                match this with 
                | Roskopp-> "Rob Roskopp..."
                | Peters -> "Duane Peters..."

let assemble model : ISkateBoard =
    match model with
    | "Roskopp" -> Roskopp :> ISkateBoard
    | "Peters" -> Peters :> ISkateBoard
    | _ -> failwith "no such skateboard model.."

let SkateBoardFactory assemble model = assemble model

let SantaCruzFactory = SkateBoardFactory assemble

这是工厂方法设计模式的适当实现吗?该模式是否在现实世界的F#应用程序中使用?

2 个答案:

答案 0 :(得分:4)

我不确定工厂方法设计模式在函数式编程中有多大作用。 模式的目标是隐藏对象的创建,以便您可以仅使用对象的抽象表示。

  • 当您以功能方式使用F#时,您将在大多数时间使用具体表示。例如,这使您能够在滑板类型上进行模式匹配。
  • 当然,F#允许您将功能风格与面向对象的风格相结合。出于某些目的,OO风格在F#中运行良好。在这种情况下,您的方法看起来很合理。

您的工厂方法可以采用具体类型(例如,区分联合)作为参数,而不是字符串。然后工厂的任务是从具体表示中构建抽象表示:

// Abstract representation of the data
type ISkateBoard = 
  abstract Model : unit -> string

// Concrete representation of the data
type SkateBoard = 
  | Roskopp 
  | Peters

现在,工厂只是SkateBoard -> ISkateBoard类型的函数。例如(使用F#对象表达式):

// Transform concrete representation to abstract representation 
let factory concrete = 
  match concrete with
  | Roskopp -> { new ISkateBoard with 
                   member x.Model() = "Rob Roskopp..." }
  | Peters -> { new ISkateBoard with 
                  member x.Model() = "Duane Peters..." }

我认为这种方法的好处是你可以对类型的具体表示做一些工作(例如你需要模式匹配的一些计算),但是你可以使用factory来转换具体类型为抽象类型。

这与函数式编程中的常用方法非常匹配 - 您经常使用一个数据的差异表示并在它们之间进行转换(取决于哪个表示对于特定问题更好)。

答案 1 :(得分:4)

与Tomas所说的一样,使用具体类型可以让您在开始使用工厂创建对象之前清理输入并失败。

type SkateBoard = 
    | Roskopp 
    | Peters
with 
    static member FromString = function
        | "Roskopp" -> Roskopp
        | "Peters" -> Peters            
        |  _ -> failwith "no such skateboard model.."

你会发现很多来自OO的设计模式就在功能编程中消失了。

使用SkateBoardFactory创建一个额外的函数来执行你的函数。

let SkateBoardFactory assemble model = assemble model
let SantaCruzFactory = SkateBoardFactory assemble

由于头等功能,您可以简单地指定assemble

let SantaCruzFactory = assemble