Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Exécuter du code avant le constructeur surchargé

6 réponses
Avatar
Faust
bonjour,

y'a-t-il une syntaxe particulière qui permette d'exécuter un bout de
code avant que celui du constructuer surchargé soit exécuté?

voici mon cas:

class Base
{
int Reference;

public Base(int Ref)
{
Reference = Ref;
DoSomething();
}

public virtual void DoSomething()
{
// utilisation de la valeur de Reference
}
}

class Derive : Base
{
int Reference2;
public Derive(int Ref1, int Ref2) : base(Ref1)
{
Reference2 = Ref2;
}

public override void DoSomething()
{
base.DoSomething();
// utilisation de la valeur de Reference2
}
}

mon problème est qu'avec ça, quand j'arrive à l'exécution de
Derive.DoSomething, la variable Reference2 ne contient pas Ref2 puisque
le constructuer de Base a été appelé avant celui de Derive.

sachant que cette classe Derive est un cas très particulier
d'utilisation de la classe Base et que ça n'aurait aucune signification
d'avoir un constructeur à 2 paramètres dans Base.

Comment puis-je remédier à ça?

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

"Humain du matin, petite faim. Humain du soir, pour bien recevoir" -
Proverbe Troll

6 réponses

Avatar
Sylvain Lafontaine
Erreur classique de design orienté object; qui consiste à vouloir exécuter
plus de code que nécessaire dans les constructeurs. Un constructeur
d'object ne devrait servir qu'à ça; c'est-à-dire construire un object et le
rendre semblable à un formulaire vierge. Une fois la construction terminée,
vous pouvez commencer à l'utiliser en écrivant dedans et en appelant les
propriétés et fonctions requises.

À l'évidence, dans votre cas, la fonction virtuelle DoSomething() ne devrait
pas être appelée dans le constructeur.

Pour terminer, ce qui est vrai pour les constructeurs l'est également pour
les fonctions régulières: plus vous aller mélanger de fonctionalités dans
une même fonction en lui ajoutant des paramètres, plus votre code va devenir
un labyrinthe.

--
Sylvain Lafontaine, ing.
MVP - Technologies Virtual-PC


"Faust" wrote in message
news:
bonjour,

y'a-t-il une syntaxe particulière qui permette d'exécuter un bout de code
avant que celui du constructuer surchargé soit exécuté?

voici mon cas:

class Base
{
int Reference;

public Base(int Ref)
{
Reference = Ref;
DoSomething();
}

public virtual void DoSomething()
{
// utilisation de la valeur de Reference
}
}

class Derive : Base
{
int Reference2;
public Derive(int Ref1, int Ref2) : base(Ref1)
{
Reference2 = Ref2;
}

public override void DoSomething()
{
base.DoSomething();
// utilisation de la valeur de Reference2
}
}

mon problème est qu'avec ça, quand j'arrive à l'exécution de
Derive.DoSomething, la variable Reference2 ne contient pas Ref2 puisque le
constructuer de Base a été appelé avant celui de Derive.

sachant que cette classe Derive est un cas très particulier d'utilisation
de la classe Base et que ça n'aurait aucune signification d'avoir un
constructeur à 2 paramètres dans Base.

Comment puis-je remédier à ça?

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

"Humain du matin, petite faim. Humain du soir, pour bien recevoir" -
Proverbe Troll



Avatar
Faust
/_Sylvain Lafontaine_ a exprimé avec précision/ :
Erreur classique de design orienté object; qui consiste à vouloir exécuter
plus de code que nécessaire dans les constructeurs. Un constructeur d'object
ne devrait servir qu'à ça; c'est-à-dire construire un object et le rendre
semblable à un formulaire vierge. Une fois la construction terminée, vous
pouvez commencer à l'utiliser en écrivant dedans et en appelant les
propriétés et fonctions requises.

À l'évidence, dans votre cas, la fonction virtuelle DoSomething() ne devrait
pas être appelée dans le constructeur.




justement, l'appel à DoSomething fait partie intégrante, à mon sens, de
l'initialisation du composant. Si elle a été externalisée dans une
procédure, c'est qu'on peut être amené à l'appeler à nouveau après en
dehors du contexte de création.

Concrêtement, cette fonction va chercher un certain nombre
d'informations en base de données pour renseigner les propriétés de
l'objet.

si je ne devrais pas faire comme ça, pour reprendre ma question de
départ toujours sans réponse, comment est-ce que je devrais m'y prendre
sachant qu'une instance de cette classe sans avoir récupéré les données
dans la base n'a *absolument* aucun sens. Comprendre, que l'utilisation
de la fonction d'initialisation des propriétés va être *systématique*.
Si j'ai mis l'appel dans le constructeur, c'est que je ne veux pas
avoir à écrire, à chaque fois:

Derive obj = new Derive();
obj.DoSometing(int1, int2);

si j'ai fait comme ça, aussi, c'est que les méthodes de classes
statiques abstraites ou virtuelles sont impossibles. En fait, à cause
de ça, mon code exact est celui ci:

class Base
{
public Base()
{
// initialisation de l'instance
}

public Base(int int1) : this()
{
// chargement des données initiales
}
}

Pour terminer, ce qui est vrai pour les constructeurs l'est également pour
les fonctions régulières: plus vous aller mélanger de fonctionalités dans une
même fonction en lui ajoutant des paramètres, plus votre code va devenir un
labyrinthe.



justement, ici, l'ajout du deuxième paramètre est une utilisation très
particulière et très ciblée de la classe de base. Si je suis passé par
un rajout de paramètre, c'est pour m'éviter d'avoir une deuxième
architecture de classe exactement identique mais qui aurait un
paramètre supplémentaire et qui, finalement, ne serait pratiquement
jamais utilisé... tout ça juste pour être plus joli "orienté objet"
parlant

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

"Tape d'abord, tape ensuite, et tape pour finir" - Proverbe Troll
Avatar
Sylvain Lafontaine
Écrire:

Derive obj = new Derive();
obj.DoSometing(int1, int2);

Ou encore:


Derive obj = new Derive(int1, int2);
obj.DoSometing();

ou possiblement:
Derive obj = new Derive(int1);
obj.DoSometing(int2);

sont, à mon avis, les seules façons logiques d'écrire votre code. En
écrivant cela, la personne qui va vous suivre et relire votre code va
comprendre exactement et tout de suite ce qui se passe. De plus, si elle a
besoin d'en dériver de nouvelles classes, d'en mettre plusieurs dans un
tableau ou de sérialiser le tout pour transférer ça à une autre machine, la
procédure à suivre va en découler logiquement; ce qui ne sera pas le cas si
vous agglomérez tout cela dans un appel unique à un constructeur indigeste.

Je le sais pour l'avoir déjà vécu moi-même; autant dans mon propre code à
mes débuts que dans celui des autres. En procédant de votre façon, vous -
ainsi que ceux qui vont vous suivre - allez finir par vous en manger les
doigts jusqu'à l'os. En fait, vous avez déjà commencé à vous les ronger
avec votre problème d'appel à une fonction virtuelle dans un constructeur.

Si vous ne voulez pas l'avoir à écrire à chaque fois, vous n'avez qu'à
isoler la procédure dans une fonction:

Derive CreeObject ()
{
Derive obj = new Derive();
obj.DoSometing(int1, int2);
return obj;
}

Cette logique est différente de celle à tout mettre dans l'appel au
constructeur puisque vous ne créer pas d'ornières pour une utilisation
indépendante de vos objets dans d'autres classes (dérivées ou non).

--
Sylvain Lafontaine, ing.
MVP - Technologies Virtual-PC


"Faust" wrote in message
news:
/_Sylvain Lafontaine_ a exprimé avec précision/ :
Erreur classique de design orienté object; qui consiste à vouloir
exécuter plus de code que nécessaire dans les constructeurs. Un
constructeur d'object ne devrait servir qu'à ça; c'est-à-dire construire
un object et le rendre semblable à un formulaire vierge. Une fois la
construction terminée, vous pouvez commencer à l'utiliser en écrivant
dedans et en appelant les propriétés et fonctions requises.

À l'évidence, dans votre cas, la fonction virtuelle DoSomething() ne
devrait pas être appelée dans le constructeur.




justement, l'appel à DoSomething fait partie intégrante, à mon sens, de
l'initialisation du composant. Si elle a été externalisée dans une
procédure, c'est qu'on peut être amené à l'appeler à nouveau après en
dehors du contexte de création.

Concrêtement, cette fonction va chercher un certain nombre d'informations
en base de données pour renseigner les propriétés de l'objet.

si je ne devrais pas faire comme ça, pour reprendre ma question de départ
toujours sans réponse, comment est-ce que je devrais m'y prendre sachant
qu'une instance de cette classe sans avoir récupéré les données dans la
base n'a *absolument* aucun sens. Comprendre, que l'utilisation de la
fonction d'initialisation des propriétés va être *systématique*. Si j'ai
mis l'appel dans le constructeur, c'est que je ne veux pas avoir à écrire,
à chaque fois:

Derive obj = new Derive();
obj.DoSometing(int1, int2);

si j'ai fait comme ça, aussi, c'est que les méthodes de classes statiques
abstraites ou virtuelles sont impossibles. En fait, à cause de ça, mon
code exact est celui ci:

class Base
{
public Base()
{
// initialisation de l'instance
}

public Base(int int1) : this()
{
// chargement des données initiales
}
}

Pour terminer, ce qui est vrai pour les constructeurs l'est également
pour les fonctions régulières: plus vous aller mélanger de fonctionalités
dans une même fonction en lui ajoutant des paramètres, plus votre code va
devenir un labyrinthe.



justement, ici, l'ajout du deuxième paramètre est une utilisation très
particulière et très ciblée de la classe de base. Si je suis passé par un
rajout de paramètre, c'est pour m'éviter d'avoir une deuxième architecture
de classe exactement identique mais qui aurait un paramètre supplémentaire
et qui, finalement, ne serait pratiquement jamais utilisé... tout ça juste
pour être plus joli "orienté objet" parlant

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

"Tape d'abord, tape ensuite, et tape pour finir" - Proverbe Troll



Avatar
Faust
> Si vous ne voulez pas l'avoir à écrire à chaque fois, vous n'avez qu'à isoler
la procédure dans une fonction:

Derive CreeObject ()
{
Derive obj = new Derive();
obj.DoSometing(int1, int2);
return obj;
}



j'en étais arrivé à la même conclusion sans pour autant la trouver
vraiment à mon gout: je trouve que c'est contourner un defaut du
language

Cette logique est différente de celle à tout mettre dans l'appel au
constructeur puisque vous ne créer pas d'ornières pour une utilisation
indépendante de vos objets dans d'autres classes (dérivées ou non).



bah c'est là que mon raisonnement continue, c'est que la classe est
sensée être une représentation d'un enregistrement en lecture seule de
la base de données (en fait d'une série d'enregistrements)... sauf à
vouloir créer un pseudo enregistrement (ce qui n'a pas de sens étant
donné la nature des enregistrements), il n'y a donc *aucune* raison
pour que l'objet n'aille pas chercher ses données dans la base et donc
qu'on n'appelle pas la methode DoSomething
Le but de cette classe est d'être utilisée par la couche IHM de mes
applications (pour un affichage à l'écran ou pour une impression)
la couche métier utilise une autre classe qui elle ne reçoit pas de
paramètre à la création pour charger l'enregistrement. Ce ne sont pas
les mêmes classes parce que celle qui me pose problème est une
encapsulation de plusieurs classes de la couche métier dans le but de
reproduire les relations entre les données de la base.

je trouve dommage que la syntaxe pour dériver un constructeur ne
permette pas d'ordonner les instructions de création dans la classe
dérivée... un peu comme on peut le faire en Pascal Objet par exemple
je trouve que c'est plutôt cette syntaxe qui met des ornières là où il
n'en faudrait pas... ou là où il n'en aurait pas fallu

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

"De tous ceux qui n'ont rien à dire, les plus agréables sont ceux qui
se taisent." - Coluche
Avatar
Messenger of the red snake mountain
Bonjour,

Une seconde opinion si cela peut vous aider dans votre choix....

Comme le précise S. Lafontaine, le constructeur est là pour construire,
pas pour 'meubler'. Vous semblez clairement vouloir 'meubler' de
manière 'implicite'.

Sans vouloir trop m'aventurer dans le "c'est bon", "c'est mauvais", je crois
qu'il n'est jamais bon de vouloir 'impliciter' des choses dans le code.
Encapsuler oui mais pas impliciter.

Vous y verrez un gain car vous êtes le premier utilisateur de cette
fonctionnalité. Votre argument de vouloir créer cette méthode DoSomething
est juste: si l'instance doit subir une nouvelle initialisation après avoir
été instanciée, le développeur doit pouvoir le faire.

Mais la réflexion va également dans l'autre sens, qu'est-ce qui vous garantit
qu'il sera toujours nécessaire d'effectuer cette opération de manière combinée
lors de l'instanciation ?

De plus, initialiser de manière explicite (appel de la méthode DoSomething
après la construction) l'instance en question pourra vous être bénéfique plus
tard dans le cas d'une éventuelle maintenance ou déboguage.

Finalement , pourquoi ne pas utiliser un constructeur statique ? Ils sont
couramment utilisés lors d'applications de certains 'patterns' de développement
surtout lorsqu'il s'agit de déterminer quelle classe devra spécifiquement
instanciée. Mais il y a un autre usage, plus orienté vers la sémantique,
dans la mesure où l'on peut 'expliciter' ces opérations que vous souhaitez
effectuer tout en conservant cette encapsulation que vous cherchez à
obtenir:

// instanciation + autres traitements - le code montre clairement que
// qu'il ne s'agit pas d'un simple 'new'
Derive d = Derive.GetInitializedInstance(a,b);

// la construction simple reste possible
Derive d = new Derive();
Derive d = new Derive(a,b);
...

Juste un avis hein, pas taper = )

Antonio
Avatar
Faust
/Après mure réflexion, _Messenger of the red snake mountain_ a écrit/ :
Bonjour,

Une seconde opinion si cela peut vous aider dans votre choix....

Comme le précise S. Lafontaine, le constructeur est là pour construire,
pas pour 'meubler'. Vous semblez clairement vouloir 'meubler' de
manière 'implicite'.

Sans vouloir trop m'aventurer dans le "c'est bon", "c'est mauvais", je crois
qu'il n'est jamais bon de vouloir 'impliciter' des choses dans le code.
Encapsuler oui mais pas impliciter.

Vous y verrez un gain car vous êtes le premier utilisateur de cette
fonctionnalité. Votre argument de vouloir créer cette méthode DoSomething
est juste: si l'instance doit subir une nouvelle initialisation après avoir
été instanciée, le développeur doit pouvoir le faire.

Mais la réflexion va également dans l'autre sens, qu'est-ce qui vous garantit
qu'il sera toujours nécessaire d'effectuer cette opération de manière
combinée
lors de l'instanciation ?



simplement parce que c'est moi qui définit ces classes et leurs
usages... c'est déjà pas mal et suffisant :)

comme je l'ai expliqué dans un autre post, j'ai justement 2 types de
classes: celle ci qui ne sert qu'à être manipulé pour affichage ou
impression et une autre qui permet la manipulation de données (création
et modification)
ce deuxième type de classe peut effectivement ne pas avoir besoin
d'être implicitement renseignée puisqu'il peut s'agir d'une création.
En revanche, la
classe qui m'interresse ne aucun présente aucun intérêt sans ses
données puisque elle n'en permet aucune manipulation autre que
l'affichage ou l'impression. Il devient donc "impératif" qu'elle
récupère des données dans la base.

De plus, initialiser de manière explicite (appel de la méthode DoSomething
après la construction) l'instance en question pourra vous être bénéfique plus
tard dans le cas d'une éventuelle maintenance ou déboguage.



pour moi, à partir du moment où la définition de la classe est
"représentation architecturée des données de la base", il est clair que
l'instanciation doit récupérer les données et donc la maintenance ou le
débugage reste simple.

Finalement , pourquoi ne pas utiliser un constructeur statique ? Ils sont
couramment utilisés lors d'applications de certains 'patterns' de
développement



c'est malheureusement ce que je vais devoir faire, mais je regrette
qu'il ne soit pas possible de redéfinir l'ordre d'exécution pour le
constructor alors que ça l'ait parfaitement pour les méthodes

Juste un avis hein, pas taper = )



si j'ai posé la question c'est que je voulais des avis ;)

--
Mephitiquement votre,
Faust
ICQ #161252577