可以为从接口继承的类型创建一个多态工厂吗?
Can one have a polymorphic factory for types inheriting from an interface?
根据 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
将无法编译,因为它会 return 不同类型的对象。
一种替代方法是将 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
会编译,但它的 return 值(我相信)是无用的,除非向下转换为 X、Y 或 Z。但这又引发了多态性问题:一般向下转换我需要一个 returns 不同类型值的函数。
另一种选择是使用歧视联盟
type ClassDU =
| XClass of X
| YClass of Y
| ZClass of Z
并使用上面定义的函数create
。但这是行不通的。如果不向上转换,编译器仍然会将不同的情况视为具有不同的类型。由于 ClassDU 不是 class,因此无法向上转换为 ClassDU。
在此代码段中
http://fssnip.net/k6/title/-F-Factory-Pattern
使用抽象 class XYZ 解决了问题,X、Y 和 Z 将从中继承抽象方法 foo。类似于 create
的函数会将所有情况向上转换为抽象 class:
let create2 (str: string) =
match str with
| "X" -> X(zX) :> XYZ
| "Y" -> Y(zY) :> XYZ
| "Z" -> Z(zZ) :> XYZ
| _ -> failwith "Something went wrong"
是否可以为从接口继承的类型创建多态工厂,或者是否必须像代码片段中那样创建抽象 class?
接口
要对接口执行此操作,您只需向上转换为接口类型,例如:
let create (str: string) =
match str with
| "X" -> X(zX) :> IFace
| "Y" -> Y(zY) :> IFace
| "Z" -> Z(zZ) :> IFace
| _ -> failwith "Something went wrong"
这有类型签名:
val create : str:string -> IFace
受歧视的工会
要对 DU 执行此操作,您需要在 create
函数中添加适当的 case 构造函数。
type ClassDU =
| XClass of X
| YClass of Y
| ZClass of Z
let createDU (str: string) =
match str with
| "X" -> XClass <| X(zX)
| "Y" -> YClass <| Y(zY)
| "Z" -> ZClass <| Z(zZ)
| _ -> failwith "Something went wrong"
这有类型签名:
val createDU : str:string -> ClassDU
我认为您对受歧视工会行为的误解源于这样一个事实,即您认为它们就像是抽象的 类 具有多个 sub类,将它们看作具有多个构造函数.
的单一类型更好更准确
根据 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
将无法编译,因为它会 return 不同类型的对象。
一种替代方法是将 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
会编译,但它的 return 值(我相信)是无用的,除非向下转换为 X、Y 或 Z。但这又引发了多态性问题:一般向下转换我需要一个 returns 不同类型值的函数。
另一种选择是使用歧视联盟
type ClassDU =
| XClass of X
| YClass of Y
| ZClass of Z
并使用上面定义的函数create
。但这是行不通的。如果不向上转换,编译器仍然会将不同的情况视为具有不同的类型。由于 ClassDU 不是 class,因此无法向上转换为 ClassDU。
在此代码段中
http://fssnip.net/k6/title/-F-Factory-Pattern
使用抽象 class XYZ 解决了问题,X、Y 和 Z 将从中继承抽象方法 foo。类似于 create
的函数会将所有情况向上转换为抽象 class:
let create2 (str: string) =
match str with
| "X" -> X(zX) :> XYZ
| "Y" -> Y(zY) :> XYZ
| "Z" -> Z(zZ) :> XYZ
| _ -> failwith "Something went wrong"
是否可以为从接口继承的类型创建多态工厂,或者是否必须像代码片段中那样创建抽象 class?
接口
要对接口执行此操作,您只需向上转换为接口类型,例如:
let create (str: string) =
match str with
| "X" -> X(zX) :> IFace
| "Y" -> Y(zY) :> IFace
| "Z" -> Z(zZ) :> IFace
| _ -> failwith "Something went wrong"
这有类型签名:
val create : str:string -> IFace
受歧视的工会
要对 DU 执行此操作,您需要在 create
函数中添加适当的 case 构造函数。
type ClassDU =
| XClass of X
| YClass of Y
| ZClass of Z
let createDU (str: string) =
match str with
| "X" -> XClass <| X(zX)
| "Y" -> YClass <| Y(zY)
| "Z" -> ZClass <| Z(zZ)
| _ -> failwith "Something went wrong"
这有类型签名:
val createDU : str:string -> ClassDU
我认为您对受歧视工会行为的误解源于这样一个事实,即您认为它们就像是抽象的 类 具有多个 sub类,将它们看作具有多个构造函数.
的单一类型更好更准确