Suite à des conseils dans SO et d'autres endroits, j'ai essayé d'implémenter le polymorphisme en utilisant des interfaces, comme dans l'exemple simplifié suivant.Peut-on avoir une fabrique polymorphique pour les types héritant d'une interface?
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
Ces valeurs peuvent être utilisées par les constructeurs de X, Y et Z:
let zX = 1
let zY = "2"
let zZ = 3.0
Je voudrais construire une usine polymorphes comme
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"
Cependant, create
sera pas compiler car il renverrait des objets de types différents.
Une alternative serait de transtyper tous les cas 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"
Puis create1
mais sa compilation aurait valeur de retour serait (je crois) inutile à moins baissés à X, Y ou Z Mais cela soulève à nouveau le problème du polymorphisme: pour redescendre génériquement, j'aurais besoin d'une fonction qui renvoie des valeurs de différents types.
Une autre alternative serait d'utiliser une Union discriminés
type ClassDU =
| XClass of X
| YClass of Y
| ZClass of Z
et utilisez la fonction create
définie ci-dessus. Mais ça ne marche pas. Sans upcasting le compilateur voit toujours les différents cas comme ayant différents types. Et upcasting à ClassDU ne fonctionne pas puisque ClassDU n'est pas une classe.
Dans ce code snippet
http://fssnip.net/k6/title/-F-Factory-Pattern
le problème est résolu en utilisant une classe abstraite XYZ à partir de laquelle X, Y et Z hériterait la méthode abstraite foo. La fonction analogue à create
serait transtyper tous les cas à la classe abstraite:
let create2 (str: string) =
match str with
| "X" -> X(zX) :> XYZ
| "Y" -> Y(zY) :> XYZ
| "Z" -> Z(zZ) :> XYZ
| _ -> failwith "Something went wrong"
Est-il possible de créer une usine polymorphes pour les types héritant d'une interface ou doit-on créer une classe abstraite comme dans l'extrait de code?
J'ai suivi votre suggestion concernant les interfaces et bien sûr cela a fonctionné. Deux questions. D'abord, après avoir construit mes objets en utilisant la fonction 'create', certaines mises à jour sont devenues inutiles et le compilateur a commencé à donner des avertissements à leur sujet. Les objets que je suis en train de traiter sont-ils différents des objets que j'avais créés avant d'utiliser les constructeurs de classes régulières? Si c'est le cas, est-ce que je perds certaines fonctionnalités? Deuxièmement: que se passe-t-il si mes classes héritent de plusieurs interfaces et ne créent que des mises à jour pour l'une d'entre elles? Puis-je diffuser simultanément plusieurs interfaces? – Soldalma