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

Heritage ; constructeur ayant plusieurs parametres

4 réponses
Avatar
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 ?

Merci d'avance pour vos conseils...

4 réponses

Avatar
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.

Avatar
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.

Avatar
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


Avatar
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.