根据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"
是否可以为从接口继承的类型创建多态工厂,还是必须像在代码片段中那样创建抽象类?