Heritage ; constructeur ayant plusieurs parametres
4 réponses
Fabien LE LEZ
Bonjour,
Soit une classe A, dont le constructeur a pas mal de paramètres.
Cette classe sert de base à une hiérarchie de classes assez touffue,
et qui peut encore être agrandie.
La plupart des classes sont non-abstraites, et peuvent être
instanciées directement.
Le problème est le passage des paramètres :
class A
{
public:
A (une_tres_longue_liste_de_parametres);
};
class B: public A
{
public:
B (une_tres_longue_liste_de_parametres);
};
B::B (une_tres_longue_liste_de_parametres)
: A (la_tres_longue_liste_de_parametres)
{...}
C'est vite fastidieux, et difficile à maintenir.
J'ai donc tendance à regrouper tous ces paramètres dans une classe
A::Parametres. Mais comme, dans le code appelant, les paramètres en
question ne sont pas naturellement liés (i.e. il faut aller les
chercher un peu partout), il faut systématiquement créer un nouvel
objet A::Parametres, ce qui rend le code plus touffu.
En d'autres termes, cette solution simplifie l'écriture des classes,
mais complique le code appelant.
Y a-t-il un moyen de ménager la chèvre et le chou ?
Cette action est irreversible, confirmez la suppression du commentaire ?
Signaler le commentaire
Veuillez sélectionner un problème
Nudité
Violence
Harcèlement
Fraude
Vente illégale
Discours haineux
Terrorisme
Autre
Sylvain
Fabien LE LEZ wrote on 10/07/2007 12:10:
Soit une classe A, dont le constructeur a pas mal de paramètres. Cette classe sert de base à une hiérarchie de classes assez touffue, et qui peut encore être agrandie. La plupart des classes sont non-abstraites, et peuvent être instanciées directement.
Le problème est le passage des paramètres : [...]
J'ai donc tendance à regrouper tous ces paramètres dans une classe A::Parametres. Mais comme, dans le code appelant, les paramètres en question ne sont pas naturellement liés (i.e. il faut aller les chercher un peu partout), il faut systématiquement créer un nouvel objet A::Parametres, ce qui rend le code plus touffu. En d'autres termes, cette solution simplifie l'écriture des classes, mais complique le code appelant.
Y a-t-il un moyen de ménager la chèvre et le chou ?
la façon (je ne dis pas la 'bonne' façon) de faire est nécessairement dépendante du design de la hiérarchie de classes. dans mon expérience, il est rare qu'une classe dérivée augmente le nb des paramètres, au contraire si la classe de base a de très nombreux paramètres, les classes filles réduisent le nombre de paramètres de leurs constructeurs car ils transmettent au constructeur de la classe de base des constantes caractéristiques de leur spécialisation - dit autrement si la classe de base est largement paramétré pour gérer de nombreux cas, les classes dérivés imposent certains paramètres.
reste néanmoins le cas où ces classes (base et dérivées) exigent de nombreux paramètres; j'ai alors tendance à définir des constructeurs sans *aucun* paramétre qui initialisent l'instance à un état généralement non opérationnel (stable et prédictible mais non initialisé); une méthode ou plusieurs méthodes viennent ensuite initialiser l'instance à un état opérationnel.
les nombreux params d'initialisation étant généralement des plain old data, j'ai tendance à définir une struct avec ces params seuls (ie une struct tout publique sans méthode) qui ne correspondent pas nécessairement aux variables de la classe (c'est sûrement proche de ton A::Parametres, bien que ce ne soit pas lié à la définition interne de A); pour initialier une classe dérivée B qui a besoin de plus de params, je définis simplement une struct (B::Params dans ton cas) étendant A::Params avec les nouveaux params nécessaires à B.
toutefois cette approche a du sens si les struct paramètres ont besoin d'exister en soi - par exemple si ils correspondent à des formats sérialisés ou d'échanges, si leur seule finalité devait servir un constructeur, je préférerais une version longue du constructeur (... quitte à le redesigner).
Sylvain.
Fabien LE LEZ wrote on 10/07/2007 12:10:
Soit une classe A, dont le constructeur a pas mal de paramètres.
Cette classe sert de base à une hiérarchie de classes assez touffue,
et qui peut encore être agrandie.
La plupart des classes sont non-abstraites, et peuvent être
instanciées directement.
Le problème est le passage des paramètres :
[...]
J'ai donc tendance à regrouper tous ces paramètres dans une classe
A::Parametres. Mais comme, dans le code appelant, les paramètres en
question ne sont pas naturellement liés (i.e. il faut aller les
chercher un peu partout), il faut systématiquement créer un nouvel
objet A::Parametres, ce qui rend le code plus touffu.
En d'autres termes, cette solution simplifie l'écriture des classes,
mais complique le code appelant.
Y a-t-il un moyen de ménager la chèvre et le chou ?
la façon (je ne dis pas la 'bonne' façon) de faire est nécessairement
dépendante du design de la hiérarchie de classes.
dans mon expérience, il est rare qu'une classe dérivée augmente le nb
des paramètres, au contraire si la classe de base a de très nombreux
paramètres, les classes filles réduisent le nombre de paramètres de
leurs constructeurs car ils transmettent au constructeur de la classe de
base des constantes caractéristiques de leur spécialisation - dit
autrement si la classe de base est largement paramétré pour gérer de
nombreux cas, les classes dérivés imposent certains paramètres.
reste néanmoins le cas où ces classes (base et dérivées) exigent de
nombreux paramètres; j'ai alors tendance à définir des constructeurs
sans *aucun* paramétre qui initialisent l'instance à un état
généralement non opérationnel (stable et prédictible mais non
initialisé); une méthode ou plusieurs méthodes viennent ensuite
initialiser l'instance à un état opérationnel.
les nombreux params d'initialisation étant généralement des plain old
data, j'ai tendance à définir une struct avec ces params seuls (ie une
struct tout publique sans méthode) qui ne correspondent pas
nécessairement aux variables de la classe (c'est sûrement proche de ton
A::Parametres, bien que ce ne soit pas lié à la définition interne de
A); pour initialier une classe dérivée B qui a besoin de plus de params,
je définis simplement une struct (B::Params dans ton cas) étendant
A::Params avec les nouveaux params nécessaires à B.
toutefois cette approche a du sens si les struct paramètres ont besoin
d'exister en soi - par exemple si ils correspondent à des formats
sérialisés ou d'échanges, si leur seule finalité devait servir un
constructeur, je préférerais une version longue du constructeur (...
quitte à le redesigner).
Soit une classe A, dont le constructeur a pas mal de paramètres. Cette classe sert de base à une hiérarchie de classes assez touffue, et qui peut encore être agrandie. La plupart des classes sont non-abstraites, et peuvent être instanciées directement.
Le problème est le passage des paramètres : [...]
J'ai donc tendance à regrouper tous ces paramètres dans une classe A::Parametres. Mais comme, dans le code appelant, les paramètres en question ne sont pas naturellement liés (i.e. il faut aller les chercher un peu partout), il faut systématiquement créer un nouvel objet A::Parametres, ce qui rend le code plus touffu. En d'autres termes, cette solution simplifie l'écriture des classes, mais complique le code appelant.
Y a-t-il un moyen de ménager la chèvre et le chou ?
la façon (je ne dis pas la 'bonne' façon) de faire est nécessairement dépendante du design de la hiérarchie de classes. dans mon expérience, il est rare qu'une classe dérivée augmente le nb des paramètres, au contraire si la classe de base a de très nombreux paramètres, les classes filles réduisent le nombre de paramètres de leurs constructeurs car ils transmettent au constructeur de la classe de base des constantes caractéristiques de leur spécialisation - dit autrement si la classe de base est largement paramétré pour gérer de nombreux cas, les classes dérivés imposent certains paramètres.
reste néanmoins le cas où ces classes (base et dérivées) exigent de nombreux paramètres; j'ai alors tendance à définir des constructeurs sans *aucun* paramétre qui initialisent l'instance à un état généralement non opérationnel (stable et prédictible mais non initialisé); une méthode ou plusieurs méthodes viennent ensuite initialiser l'instance à un état opérationnel.
les nombreux params d'initialisation étant généralement des plain old data, j'ai tendance à définir une struct avec ces params seuls (ie une struct tout publique sans méthode) qui ne correspondent pas nécessairement aux variables de la classe (c'est sûrement proche de ton A::Parametres, bien que ce ne soit pas lié à la définition interne de A); pour initialier une classe dérivée B qui a besoin de plus de params, je définis simplement une struct (B::Params dans ton cas) étendant A::Params avec les nouveaux params nécessaires à B.
toutefois cette approche a du sens si les struct paramètres ont besoin d'exister en soi - par exemple si ils correspondent à des formats sérialisés ou d'échanges, si leur seule finalité devait servir un constructeur, je préférerais une version longue du constructeur (... quitte à le redesigner).
Sylvain.
Michel Decima
toutefois cette approche a du sens si les struct paramètres ont besoin d'exister en soi - par exemple si ils correspondent à des formats sérialisés ou d'échanges, si leur seule finalité devait servir un constructeur, je préférerais une version longue du constructeur (... quitte à le redesigner).
Pas seulement. Ca permet de ne preciser que certains parametres, en utilisant les valeurs par defaut pour les autres, sans avoir le probleme des parametres optionnels de fonction.
toutefois cette approche a du sens si les struct paramètres ont besoin
d'exister en soi - par exemple si ils correspondent à des formats
sérialisés ou d'échanges, si leur seule finalité devait servir un
constructeur, je préférerais une version longue du constructeur (...
quitte à le redesigner).
Pas seulement. Ca permet de ne preciser que certains parametres, en
utilisant les valeurs par defaut pour les autres, sans avoir le probleme
des parametres optionnels de fonction.
toutefois cette approche a du sens si les struct paramètres ont besoin d'exister en soi - par exemple si ils correspondent à des formats sérialisés ou d'échanges, si leur seule finalité devait servir un constructeur, je préférerais une version longue du constructeur (... quitte à le redesigner).
Pas seulement. Ca permet de ne preciser que certains parametres, en utilisant les valeurs par defaut pour les autres, sans avoir le probleme des parametres optionnels de fonction.
James Kanze
On Jul 10, 1:11 pm, Michel Decima wrote:
toutefois cette approche a du sens si les struct paramètres ont besoin d'exister en soi - par exemple si ils correspondent à des formats sérialisés ou d'échanges, si leur seule finalité devait servir un constructeur, je préférerais une version longue du constructeur (... quitte à le redesigner).
Pas seulement. Ca permet de ne preciser que certains parametres, en utilisant les valeurs par defaut pour les autres, sans avoir le probleme des parametres optionnels de fonction.
C'est en effet une solution assez classique dans le domaine des GUI. On définit une classe du genre WindowParams, avec des fonctions du genre backgroundColor(), size(), etc., qui renvoie une référence à l'objet. La classe s'initialise avec des valeurs par défaut (ou avec un constructeur de copie, d'un objet qui représente un défaut local), et on appelle ensuite les fonctions qu'on veut pour modifier les valeurs où le défaut ne convient pas : new XXXPanel( WindowParams().textColor( red ) ) ou : new XXXPanel( WindowParams( navigatorDefaults ).textColor( red ) ) ; par exemple. (Le constructeur de XXXPanel prend un seul paramètre, de type WindowParams const&.)
Je n'ai pas vu cette solution ailleurs que dans les GUI, en revanche.
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
On Jul 10, 1:11 pm, Michel Decima <michel.dec...@orange-ft.com> wrote:
toutefois cette approche a du sens si les struct paramètres ont besoin
d'exister en soi - par exemple si ils correspondent à des formats
sérialisés ou d'échanges, si leur seule finalité devait servir un
constructeur, je préférerais une version longue du constructeur (...
quitte à le redesigner).
Pas seulement. Ca permet de ne preciser que certains parametres, en
utilisant les valeurs par defaut pour les autres, sans avoir le probleme
des parametres optionnels de fonction.
C'est en effet une solution assez classique dans le domaine des
GUI. On définit une classe du genre WindowParams, avec des
fonctions du genre backgroundColor(), size(), etc., qui renvoie
une référence à l'objet. La classe s'initialise avec des valeurs
par défaut (ou avec un constructeur de copie, d'un objet qui
représente un défaut local), et on appelle ensuite les fonctions
qu'on veut pour modifier les valeurs où le défaut ne convient
pas :
new XXXPanel( WindowParams().textColor( red ) )
ou :
new
XXXPanel( WindowParams( navigatorDefaults ).textColor( red ) ) ;
par exemple. (Le constructeur de XXXPanel prend un seul
paramètre, de type WindowParams const&.)
Je n'ai pas vu cette solution ailleurs que dans les GUI, en
revanche.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
toutefois cette approche a du sens si les struct paramètres ont besoin d'exister en soi - par exemple si ils correspondent à des formats sérialisés ou d'échanges, si leur seule finalité devait servir un constructeur, je préférerais une version longue du constructeur (... quitte à le redesigner).
Pas seulement. Ca permet de ne preciser que certains parametres, en utilisant les valeurs par defaut pour les autres, sans avoir le probleme des parametres optionnels de fonction.
C'est en effet une solution assez classique dans le domaine des GUI. On définit une classe du genre WindowParams, avec des fonctions du genre backgroundColor(), size(), etc., qui renvoie une référence à l'objet. La classe s'initialise avec des valeurs par défaut (ou avec un constructeur de copie, d'un objet qui représente un défaut local), et on appelle ensuite les fonctions qu'on veut pour modifier les valeurs où le défaut ne convient pas : new XXXPanel( WindowParams().textColor( red ) ) ou : new XXXPanel( WindowParams( navigatorDefaults ).textColor( red ) ) ; par exemple. (Le constructeur de XXXPanel prend un seul paramètre, de type WindowParams const&.)
Je n'ai pas vu cette solution ailleurs que dans les GUI, en revanche.
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Michel Decima
C'est en effet une solution assez classique dans le domaine des GUI. On définit une classe du genre WindowParams, avec des fonctions du genre backgroundColor(), size(), etc., [couic]
C'est bien a ce genre d'utilisation que je pensais.
Je n'ai pas vu cette solution ailleurs que dans les GUI, en revanche.
Elle est aussi utilisee dans Boost.Graph, pour passer des arguments aux algorithmes de calcul. Les algorithmes en question ont souvent une dizaine d'argument, et la plupart du temps on a seulement besoin d'en preciser 2 ou 3, et on garde les valeurs par defaut pour les autres.
C'est en effet une solution assez classique dans le domaine des
GUI. On définit une classe du genre WindowParams, avec des
fonctions du genre backgroundColor(), size(), etc.,
[couic]
C'est bien a ce genre d'utilisation que je pensais.
Je n'ai pas vu cette solution ailleurs que dans les GUI, en
revanche.
Elle est aussi utilisee dans Boost.Graph, pour passer des
arguments aux algorithmes de calcul. Les algorithmes en question
ont souvent une dizaine d'argument, et la plupart du temps on
a seulement besoin d'en preciser 2 ou 3, et on garde les valeurs
par defaut pour les autres.
C'est en effet une solution assez classique dans le domaine des GUI. On définit une classe du genre WindowParams, avec des fonctions du genre backgroundColor(), size(), etc., [couic]
C'est bien a ce genre d'utilisation que je pensais.
Je n'ai pas vu cette solution ailleurs que dans les GUI, en revanche.
Elle est aussi utilisee dans Boost.Graph, pour passer des arguments aux algorithmes de calcul. Les algorithmes en question ont souvent une dizaine d'argument, et la plupart du temps on a seulement besoin d'en preciser 2 ou 3, et on garde les valeurs par defaut pour les autres.