OVH Cloud OVH Cloud

Casse-tête de structure de class

17 réponses
Avatar
Faust
(je suis avec le framework 1.1)

j'essaye d'obtenir une structure de classe assez simple (en tous cas
sur le papier) mais je bloque dessus:

j'aimerais avoir une classe parente abstraite qui contiendait (au
moins) une méthode statique permettant (entre autre) de créer puis
d'initialiser une instance de la classe enfant

mon deuxième mais moins important problème est que l'une des classes
enfant necessite des paramètres supplémentaires

en gros, avoir ça mais je bloque sur le codage de init():

public abstract class parent
{
public virtual void Fill(object param1)
{
}

static public ????? init(object param1)
{
// creation de l'objet de classe enfant
???? tmp = new ????();
// initialisation
tmp.Fill(param1);
return tmp;
}
}

public class enfant1 : parent
{
public override void Fill(object param1)
{
// initialisation propre à la classe enfant1
}
}

public class enfant2 : parent
{
public override void Fill(object param1, object param2)
{
// initialisation propre à la classe enfant2
}
}

--
*/Teträm/*
http://www.tetram.org

"Quand le Troll parle,
L'homme avisé l'écoute"

10 réponses

1 2
Avatar
Ambassadeur Kosh
tu peux faire comme ça, si tu veux limiter les instances pour offrir des
fonctionalités restreintes.

public abstract class Test
{
protected Test() {}

public abstract f() ;

public static readonly Test Test1 = new Test1() ;
public static readonly Test Test2 = new Test2() ;

private sealed class Test1 : Test {...}
private sealed class Test2 : Test {...}
}

sinon, si tu veux creer une instance, tu peux mettre ça dans une Factory,
bien que l'interet de la factory soit d'avoir un peu de dynamique. ou alors,
tu ranges ça dans ta class de base, mais bon...

public static class TestFactory
{
public static Test1 CreateTest1() ...
public static Test2 CreateTest2() ...
}

mon deuxième mais moins important problème est que l'une des classes
enfant necessite des paramètres supplémentaires



ben je vois pas le probleme

public static class TestFactory
{
public static Test1 CreateTest1() { return new Test1() ; }
public static Test2 CreateTest2() { return new Test2(25.63) ; }
public static Test2 CreateTest2(object param1) { return new
Test2(param1) ; }
}

en gros, avoir ça mais je bloque sur le codage de init():



le mot Create me semble preferable à Init.
je vois des object, je me dis que la, y'a un gros souci.
sinon, pour la dynamique :

public interface ITestFactory
{
Test Create() ;
}

public sealed class Test1Factory : ITestFactory
{
Test ITestFactory.Create() { return Create() ; }
public Test1 Create() { return new Test1() ; }
}

public sealed class Test2Factory : ITestFactory
{
Test ITestFactory.Create() { return Create() ; }
public Test2 Create() { return new Test2(25.63) ; }
public Test2 Create(object p) { return new Test2(p) ; }
}


maintenant, au cas ou c'est une histoire de type qui devient un parametre du
Create, tu peux faire ça :

enum TestType { Test1 , Test2 };

public static class TestFactory
{
public static Test Create(TestType type,object p)
{
switch(type)
{
case TestType.Test1 : return new Test1() ;
case TestType.Test2 : return new Test2(p) ;
default : throw new NotImplementedException() ;
}
}
}


donc, maintenant, choisi le principe qui te convient. mais sans connaitre
plus ton probleme, je me vois mal te conseiller d'avantage...
ce probleme de parametre inutile n'est il pas la miette de pain qui cache la
montagne ? je veux dire que ce n'est peut être pas au bon endroit que tu
fais la création...

un de ces patterns t'inspire t'il plus que les autres ?

"Quand le Troll parle,
L'homme avisé l'écoute"



hmm hmm...
Avatar
Lloyd Dupont
C'est pas tres clair ton probleme....

-si Fill() ne doit pas etre appeller explicitement, pourquoi ne pas en faire
une method protected?
- comment qu'init() il sait quelle sous classe il doit instancier?

moi je verrais bien un truc comme ca:

public class Parent
{
protected abstract Fill(params object[] obj);

public static Parent CreateType1(object prm)
{
Parent p = new Enfant1();
p.Fill(obj);
return p;
}
public static Parent CreateType2(object prm, object prm2)
{
Parent p = new Enfant2();
p.Fill(prm, prm2);
return p;
}
public static Parent Create(params object[] prms)
{
Parent p;
switch(prms.Length)
{
defaut:
p = new Enfant1();
break;
case 2:
p = new Enfant2();
break;
}
p.Fill(prms);
return p;
}
}


--
*/Teträm/*
http://www.tetram.org

"Quand le Troll parle,
L'homme avisé l'écoute"



Les Trolls se retrouvent ensemble sur MountyHall
http://www.mountyhall.com
Pas (12385)

--
There are 10 kinds of people in this world. Those who understand binary and
those who don't.
Avatar
Faust
/_Ambassadeur Kosh_ a prétendu/ :
donc, maintenant, choisi le principe qui te convient. mais sans connaitre
plus ton probleme, je me vois mal te conseiller d'avantage...



bah pourtant j'ai pas bcp plus d'infos à proposer

mon but est d'avoir une méthode statique permettant de créer (new +
fill) une instance d'une classe enfant

ce probleme de parametre inutile n'est il pas la miette de pain qui cache la
montagne ? je veux dire que ce n'est peut être pas au bon endroit que tu fais
la création...



bah euh je vois pas où je peux le mettre d'autre... la méthode fill de
cette classe en particulier a besoin d'un paramètre supplémentaire
si je crée mon factory (ou ma méthode statique) il faut bien que je
puisse donner ce param supplémentaire

un de ces patterns t'inspire t'il plus que les autres ?



bah ce qui me gène c'est que dans tous les patterns que tu me propose,
les types enfants sont connus

ce qui fait que, certes moi je connais ceux que je vais mettre dans la
lib, mais l'utilisateur de la lib va être obligé de dériver le Factory
pour y inclure le cas de ses propres classes

"Quand le Troll parle,
L'homme avisé l'écoute"





hmm hmm...



cf le monde de la BD et la série Trolls de Troy plus particulièrement
;)

--
*/Teträm/*
http://www.tetram.org

"On a toujours tort d'essayer d'avoir raison devant des gens qui ont
toutes les bonnes raisons de croire qu'ils n'ont pas tort !" - Raymond
Devos
Avatar
Faust
/_Lloyd Dupont_ a pensé très fort/ :
C'est pas tres clair ton probleme....



-si Fill() ne doit pas etre appeller explicitement, pourquoi ne pas en faire
une method protected?



j'ai pas dit qu'il ne le pouvait pas: rien n'empêche plus tard dans la
vie de l'ojet de refaire un appel à Fill avec un autre paramètre...
mais comme le cas le plus courant est new + fill (+ GC)

- comment qu'init() il sait quelle sous classe il doit instancier?



bah c'est bien mon problème justement: il n'en sait rien
pour l'instant, pour contourner le problème, je passe le type en param
mais ça me plait que moyennement puisque ça donne:

enfant1.init(typeof(enfant1), param);

c'est à la fois idiot et dangereux parce que je pourrais tout aussi
bien ecrire:

enfant1.init(typeof(enfant2), param);

dangereux parce que ça provoquerait à coup sûr des erreur (init n'ayant
pas assez de param à passer au constructeur de enfant2)
et idiot parce qu'étant une méthode appellée par la classe enfant1 on
pourrait connaitre la classe (si this était utilisable dans les
méthodes de classe par exemple)

moi je verrais bien un truc comme ca:



[snip]

même remarque qu'à l'ambassadeur: ta proposition suppose de connaitre
tous les types enfants or je ne peux pas

--
*/Teträm/*
http://www.tetram.org

"On a toujours tort d'essayer d'avoir raison devant des gens qui ont
toutes les bonnes raisons de croire qu'ils n'ont pas tort !" - Raymond
Devos
Avatar
Faust
/_Lloyd Dupont_ a émis l'idée suivante/ :
moi je vois que trois solutions pour toi



1. etre plus reconnaissant avec les gens qui tente de t'aider



je leur suis reconnaissant mais je leur montre que les solutions qu'ils
me proposent ne me conviennent pas et j'explique pourquoi.... s'ils
n'ont pas de solutions qui me conviennent j'en suis dzl

2. aller te defouler sur www.mountyhall.com



j'ai rien à faire là-bas... par contre, je pense que tu pourrais
changer ton lit de place pour t'éviter de te lever du pied gauche le
matin

3. utiliser les generic (C# 2.0) comme montrer dans l'exemple en fichier
joint.



c'est utilisable avec le compact framework?

--
*/Teträm/*
http://www.tetram.org

"On a toujours tort d'essayer d'avoir raison devant des gens qui ont
toutes les bonnes raisons de croire qu'ils n'ont pas tort !" - Raymond
Devos
Avatar
Ambassadeur Kosh
> ce qui fait que, certes moi je connais ceux que je vais mettre dans la
lib, mais l'utilisateur de la lib va être obligé de dériver le Factory
pour y inclure le cas de ses propres classes



couplage or not couplage... dans ce cas, pas besoin de factory...
et je repose mon affirmation. plutot que de faire

public Test f(int type_dobjet_a_creer)
{
... création dynamique...
}

autant faire


public void f(Test test_to_use)
{
... création dynamique...
}

et la, c'est vachement mieux. tu as separé les choses. la construction son
taf, et ton objet le sien.

mais si tu persistes dans ta voie sers toi de la reflection, sachant que le
probleme du parametre reste entier (et pour cause)

public Test f(Type type)
...
f( typeof(Test1) ) ;

cf le monde de la BD et la série Trolls de Troy plus particulièrement ;)



ok. nous avons parfois la visite d'un pretendant au titre qui n'a rien de
Hebus, meme pas l'effet comique :)
Avatar
Faust
/_Ambassadeur Kosh_ a écrit/ :
ce qui fait que, certes moi je connais ceux que je vais mettre dans la lib,
mais l'utilisateur de la lib va être obligé de dériver le Factory pour y
inclure le cas de ses propres classes





couplage or not couplage... dans ce cas, pas besoin de factory...
et je repose mon affirmation. plutot que de faire



public Test f(int type_dobjet_a_creer)
{
... création dynamique...
}



autant faire



public void f(Test test_to_use)
{
... création dynamique...
}



et la, c'est vachement mieux. tu as separé les choses. la construction son
taf, et ton objet le sien.



mais si tu persistes dans ta voie sers toi de la reflection, sachant que le
probleme du parametre reste entier (et pour cause)



bah c'est pas que je persiste mais j'arrive pas à percuter comment
l'utiliser.... mais pour le moment j'arrive pas comprendre à quelle
classe (parent ou factory/enfant1/enfant2) correspond ta classe Test

public Test f(Type type)
...
f( typeof(Test1) ) ;



c'est effectivement ce que j'ai fait pour le moment

--
*/Teträm/*
http://www.tetram.org

"Le monde est rond comme le cul d'une pucelle. On ne peut pas s'y
perdre"
Chevalier Or-Azur
Avatar
Ambassadeur Kosh
> c'est utilisable avec le compact framework?



pas avec le 1.1. mais si tu passes en 2.0, oui

maintenant, comme viens de te le montrer Lloyd dans son sample, il se
pourrait que tu cherches Activator.
la genericité peut te faciliter grandement la vie.
mais je me demande si tu ne cherches pas à resoudre un probleme par une
mauvaise solution.

enfin, derniere idée, tant qu'on rigole :)

public abstract class Test : ICloneable
{
object ICloneable Clone() { return Clone() ; }
public abstract Test Clone() ;
}
public sealed class sealed Test1 : Test
{
public override Test Clone() { ... }
}
public sealed class sealed Test2 : Test
{
public override Test Clone() { ... }
}

...
void Job(Test instance)
{
Test item = instance.Clone() ;
}
Avatar
Faust
/Après mure réflexion, _Ambassadeur Kosh_ a écrit/ :
c'est utilisable avec le compact framework?





pas avec le 1.1. mais si tu passes en 2.0, oui



maintenant, comme viens de te le montrer Lloyd dans son sample, il se
pourrait que tu cherches Activator.



bah j'ai essayé mais le problème d'Activator c'est qu'il necessite
qu'on lui donne le type à créer...
mais dans la méthode de classe je n'ai pas réussi à récupérer une
valeur de type Type qui contient le type de la classe enfant (le this
n'est pas accessible puisqu'il ne renvoit que des objets mais pas des
classes et donc point de this.GetType() )

la genericité peut te faciliter grandement la vie.



je suis en train de regardé...

--
*/Teträm/*
http://www.tetram.org

"Tape d'abord, tape ensuite, et tape pour finir" - Proverbe Troll
Avatar
Ambassadeur Kosh
> bah c'est pas que je persiste mais j'arrive pas à percuter comment
l'utiliser.... mais pour le moment j'arrive pas comprendre à quelle classe
(parent ou factory/enfant1/enfant2) correspond ta classe Test



Test, c'est Parent.
Test1, Test2, c'est les Enfants chez toi.
et ma foi, Factory, c'est Factory...

c'est effectivement ce que j'ai fait pour le moment



ouaih bon, ça craint...

si tu n'as pas de genericité, tu peux aussi faire ça, peut être que c'est un
modele qui va mieux te parler.
c'est séduisant, mais ça se rapproche de l'heritage d'implantation, et c'est
pas terrible.

public abstract class Node { }
public sealed class SpecializedNode : Node { }

public abstract class TestAlgorithm
{
public void Execute()
{
Node node1 = CreateNode() ;
...
Node node2 = CreateNode() ;
...
}

protected abstract Node CreateNode() ;
}

public abstract class SpecializedTestAlgorithm
{
protected override Node CreateNode()
{
return new SpecializedNode() ;
}
}

enfin bon faut voir...
1 2