遵循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"
是否有可能建立一個多態工廠類型從接口繼承或沒有一個必須創建一個抽象類中的代碼片段?
我按照你的建議接口,當然它的工作。兩個問題。首先,在我用'create'函數構造我的對象之後,一些upcasts變得不必要了,編譯器開始給出警告。我現在處理的對象與使用常規類構造函數之前創建的對象有什麼不同?如果是這樣的話,我會失去一些功能嗎?第二:如果我的類繼承了幾個接口,並且「只創建」其中一個接口,會發生什麼?我可以同時上傳到多個界面嗎? – Soldalma