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

Comment donner accès à une "liste"

4 réponses
Avatar
Loïc Joly
Bonjour,

Imaginons une structure d'arbres avec la classe suivante :

class Node
{
vector<Node> listOfChildren;
// ...
};

Je souhaite permettre à l'utilisateur de cette classe de faire pas mal
de chose, comme ajouter des noeuds, en enlever, parcourir l'arbre.....

J'hésite entre plusieur interfaces possibles, et j'ai du mal à voir les
avantages des différentes solutions :

1/ Accès "direct"

class Node
{
vector<Node> listOfChildren;
public:
vector<Node> &getChildren();
vector<Node> const &getChildren() const;
};


2/ On cache tout

class Node
{
vector<Node> listOfChildren;
typedef vector<Node>::iterator SubNodeIterator;
SubNodeIterator subNodeBegin();
SubNodeIterator subNodeEnd();
void addNode(Node n);
void removeNode(int NodeId);
Node &findNode (intNodeId);
// ... et plein d'autres
};


3/ On cache à moitié

class NodeList
{
// Classe basée sur vector<Node> mais présentant une interface plus
réduite
// qui par exemple supporterait facilement le passage à un list<Node>
};

class Node
{
NodeList listOfChildren;
public:
NodeList &getChildren();
NodeList const &getChildren() const;
};


Et vous, quelle solution prendriez vous ?

--
Loïc

4 réponses

Avatar
Vivien Gallinaro
Loïc Joly wrote:

1/ Accès "direct"

class Node
{
vector<Node> listOfChildren;
public:
vector<Node> &getChildren();
vector<Node> const &getChildren() const;
};


(Désolé, c'est un poil HS) A ce propos, j'aimerais savoir : y a-t-il un
intérêt à avoir un membre privé doté d'accesseurs en lecture et en
écriture ? Quel est l'avantage comparé à un membre public ?
J'en pense que la version avec accesseurs est juste plus pénible à
écrire, parce qu'elle multiplie les noms et demande d'écrire du code
trivial.

Et vous, quelle solution prendriez vous ?


Dans un premier temps, sauf à avoir déjà une bonne idée des contraintes
sur ton type d'arbre (la sémantique, comme dit Marc), je crois que je me
contenterais d'un simple vector<Node>. Mais le "dans un premier temps"
n'est pas une formule qui minimise les risques ; c'est bon pour un
proto, quoi.

Gourgouilloult du Clapotis

Avatar
Julien Blanc
Vivien Gallinaro wrote:
Loïc Joly wrote:


1/ Accès "direct"

class Node
{
vector<Node> listOfChildren;
public:
vector<Node> &getChildren();
vector<Node> const &getChildren() const;
};



(Désolé, c'est un poil HS) A ce propos, j'aimerais savoir : y a-t-il un
intérêt à avoir un membre privé doté d'accesseurs en lecture et en
écriture ? Quel est l'avantage comparé à un membre public ?
J'en pense que la version avec accesseurs est juste plus pénible à
écrire, parce qu'elle multiplie les noms et demande d'écrire du code
trivial.


si tu as des contraintes à respecter sur ta variable, oui. Si tu veux
pouvoir changer ton implémentation sans changer ton interface, oui. En
général, je dirais oui :).

Les cas où ça n'a aucun intérêt sont à mon avis les cas de classes
finales, figées, et sans contraintes. Ca n'en fait pas tellement somme
toute...

--
Julien Blanc. Equipe cadp. VERIMAG. Grenoble. France.


Avatar
Loïc Joly
Marc Boyer wrote:
Loïc Joly wrote:

Bonjour,

Imaginons une structure d'arbres avec la classe suivante :

class Node
{
vector<Node> listOfChildren;
// ...
};

Je souhaite permettre à l'utilisateur de cette classe de faire pas mal
de chose, comme ajouter des noeuds, en enlever, parcourir l'arbre.....



Comme souvent, évolutivité et maintenabilité vont s'opposer
à la rapidité de la première écriture du code. La solution
de facilité, c'est bien sur l'accès direct.

Mais première chose me semblerait importante: pouvoir changer
de conteneur sans briser l'interface. Le jour ou ton vector te semble
inapproprié, que tu préfères autre chose, ce serait bien de pouvoir
le faire.


[...]


Par contre, je vois pas trop de différence entre la version
"a moitié caché" et la version "tout caché". De toute façon, il
faut encapsuler, écrire le code, et je ne vois pas de sémantique
propre à "NodeList"...


En fait, la version "à moitié caché" avait pour but de pouvoir justement
changer de conteneur sous-jacent de façon plus sure qu'avec un simple
typedef : La classe NodeList aurait comme interface ce qui est comme à
vector, list, deque...

--
Loïc


Avatar
Vivien Gallinaro
Julien Blanc wrote:
Vivien Gallinaro wrote:

y a-t-il
un intérêt à avoir un membre privé doté d'accesseurs en lecture et en
écriture ? Quel est l'avantage comparé à un membre public ?


En général, je dirais oui :).


Je crois qu'on ne s'est pas tout à fait compris. Je parlais uniquement
des membres pour lesquels on dispose à la fois d'un accesseur en lecture
_et_ d'un accesseur en écriture (ou bien d'un seul qui fait les deux,
mais ça l'idée est la même).

si tu as des contraintes à respecter sur ta variable, oui.


Dans ce cas là, on n'aura pas d'accesseur en écriture directe. Donc ici,
on ne retourne pas une référence, ou alors systématique une const réf...

Si tu veux
pouvoir changer ton implémentation sans changer ton interface, oui.


Dans le cas présent, sauf quelques cas bien particuliers (utilisation de
push_front() et genre), l'interface est la même. Ensuite, si on parle
bien d'un membre privé, sur lequel une méthode renvoie une référence
(accesseur en écriture), c'est de toute façon à l'appelant de se manger
la divergence d'interface, non ?

Un autre souci assez fréquent de non-compréhension dans ce groupe, j'ai
cru remarqué, c'est quand plusieurs interlocuteurs ne restent pas au
même niveau d'abstraction. Par exemple, là, j'aurais du mal à dire à
quel point je reste connecté à l'exemple de départ, ou à quel point j'ai
tort de l'être encore...

Les cas où ça n'a aucun intérêt sont à mon avis les cas de classes
finales, figées, et sans contraintes. Ca n'en fait pas tellement somme
toute...


On peut sans doute rajouter les structs, non ? Ces petites classes qui
n'ont comme seul intérêt que d'aggréger quelques données. Ah ben tiens,
c'est justement des classes finales, figées et sans contraintes ;)
Mais c'est quand même un exemple d'usage qui n'a pas l'air improbable. Si ?

Gourgouilloult du Clapotis