对于从接口继承的类型,可以有一个多态工厂吗?

时间:2017-05-07 14:59:39

标签: interface f# polymorphism abstract-class discriminated-union

根据SO和其他地方的建议,我尝试使用接口实现多态性,如下面的简化示例所示。

type IFace =
   // abstract methods
   abstract member foo: int -> int

type X(i: int) =
    // some code
    interface IFace with
        member this.foo j = i + j

type Y(s: string) =
    // some code
    interface IFace with
        member this.foo j = (int s) + j

type Z(x: float) =
    // some code
    interface IFace with
        member this.foo j = (int x) + j

这些值可以由X,Y和Z的构造函数使用:

let zX = 1
let zY = "2"
let zZ = 3.0

我想构建像

这样的多态工厂
let create (str: string) =
    match str with
    | "X" -> X(zX)
    | "Y" -> Y(zY)
    | "Z" -> Z(zZ)
    | _ -> failwith "Something went wrong"

let XObj = create "X"    
let YObj = create "Y"
let ZObj = create "Z"

但是,create将无法编译,因为它将返回不同类型的对象。

另一种方法是将create中的所有案例转发到System.Object:

let create1 (str: string) =
    match str with
    | "X" -> X(zX) :> System.Object
    | "Y" -> Y(zY) :> System.Object
    | "Z" -> Z(zZ) :> System.Object
    | _ -> failwith "Something went wrong"

然后create1会编译,但是它的返回值会(我相信)无效,除非向下转换为X,Y或Z.但是这再次引发了多态性问题:一般情况下,我需要一个返回的函数不同类型的价值观。

另一种选择是使用歧视联盟

type ClassDU =
    | XClass of X
    | YClass of Y
    | ZClass of Z

并使用上面定义的函数create。但这不起作用。在没有向上转换的情况下,编译器仍然将不同的情况视为具有不同类型。由于ClassDU不是类,因此向ClassDU的向上转换不起作用。

在此代码段中

http://fssnip.net/k6/title/-F-Factory-Pattern

使用抽象类XYZ解决问题,X,Y和Z将从该抽象类继承抽象方法foo。类似于create的函数会将所有情况向上转换为抽象类:

let create2 (str: string) =
    match str with
    | "X" -> X(zX) :> XYZ
    | "Y" -> Y(zY) :> XYZ
    | "Z" -> Z(zZ) :> XYZ
    | _ -> failwith "Something went wrong"

是否可以为从接口继承的类型创建多态工厂,还是必须像在代码片段中那样创建抽象类?

0 个答案:

没有答案