web-dev-qa-db-fra.com

Meilleures pratiques pour l'utilisation des espaces de noms en C ++

J'ai lu l'oncle Bob Clean Code il y a quelques mois, et cela a eu un impact profond sur la façon dont j'écris du code. Même s'il semblait répéter des choses que chaque programmeur devrait savoir, les rassembler et les mettre en pratique aboutit à un code beaucoup plus propre. En particulier, j'ai trouvé que la décomposition de grandes fonctions en de nombreuses fonctions minuscules et la décomposition de grandes classes en de nombreuses classes minuscules étaient incroyablement utiles.

Maintenant pour la question. Les exemples du livre sont tous en Java, alors que je travaille en C++ depuis plusieurs années. Comment les idées de Clean Code pourraient-elles s’étendre à l’utilisation d’espaces de noms, qui n’existent pas en Java? (Oui, je connais les packages Java, mais ce n'est pas vraiment la même chose.)

Est-il judicieux d'appliquer l'idée de créer de nombreuses petites entités, chacune avec une responsabilité clairement définie, aux espaces de noms? Un petit groupe de classes liées doit-il toujours être enveloppé dans un espace de noms? Est-ce la façon de gérer la complexité d'avoir beaucoup de petites classes, ou le coût de la gestion de nombreux espaces de noms serait-il prohibitif?

Edit: ma question est répondue dans ce entrée Wikipedia sur les principes de package .

39
Dima

(Je n'ai pas lu Clean Code et je ne connais pas beaucoup Java.)

Est-il judicieux d'appliquer l'idée de créer de nombreuses petites entités, chacune avec une responsabilité clairement définie, aux espaces de noms?

Oui, tout comme pour le refactoring en plusieurs classes et plusieurs fonctions.

Un petit groupe de classes liées doit-il toujours être enveloppé dans un espace de noms?

Sans vraiment répondre: oui, vous devez au moins utiliser un espace de noms de niveau supérieur. Cela peut être basé sur un projet, une organisation ou tout ce que vous voulez, mais l'utilisation de quelques noms globaux réduira les conflits de noms. Un seul espace de noms pour regrouper tout le reste ne présente qu'un seul nom global. (À l'exception des fonctions externes "C", mais cela est dû à l'interopérabilité C et n'affecte que les autres fonctions externes "C".)

Un petit groupe de classes liées doit-il être enveloppé dans un espace de noms qui leur est dédié? Probablement. Surtout si vous vous retrouvez à utiliser un préfixe commun sur ces classes - FrobberThing, FrobberThang, FrobberDoohickey - vous devriez envisager un espace de noms - frobber :: Thing et ainsi de suite. Ce serait toujours sous votre espace de noms racine ou un autre espace de noms s'ils font partie d'un projet plus vaste.

Est-ce la façon de gérer la complexité d'avoir beaucoup de petites classes, ou le coût de la gestion de nombreux espaces de noms serait-il prohibitif?

En prenant l'exemple ci-dessus de noms préfixés, il n'est pas plus difficile de gérer frobber :: Thing que FrobberThing. Cela peut même être plus facile avec certains outils, tels que la documentation et la complétion de code. Il y a une différence avec ADL, mais cela peut jouer en votre faveur: moins de noms dans les espaces de noms associés rendent ADL plus simple à comprendre, et vous pouvez utiliser des déclarations pour injecter des noms spécifiques dans un espace de noms ou un autre.

Les alias d'espace de noms vous permettent d'utiliser un nom plus court pour un espace de noms plus long dans un contexte spécifique, ce qui permet à nouveau une utilisation plus facile:

void f() {
  namespace CWVLN = Company_with_very_long_name;  // Example from the standard.
  // In this scope, use CWVLN::name instead of Company_with_very_long_name::name.
  namespace fs = boost::filesystem;  // Commonly used.
}

Considérez Boost, qui a un seul espace de noms racine, boost, puis de nombreux sous-noms - boost :: asio, boost :: io, boost :: filesystem, boost :: tuples, etc. - pour diverses bibliothèques. Certains noms sont "promus" vers l'espace de noms racine:

Toutes les définitions sont dans namespace :: boost :: tuples, mais les noms les plus courants sont levés vers namespace :: boost avec l'utilisation de déclarations. Ces noms sont: Tuple, make_Tuple, tie and get. De plus, ref et cref sont définis directement sous l'espace de noms :: boost.

La plus grande différence avec les langues avec des modules "réels" est la fréquence d'utilisation d'une structure plus plate, ce qui se produit principalement parce que c'est ainsi que cela fonctionne, à moins que vous ne fassiez des efforts supplémentaires et spécifiques pour définir des noms imbriqués.

23
Fred Nurk

Vous devez avoir un espace de noms principal pour tout votre code. Cela le distingue du code externe en ce qui concerne les espaces de noms.

Dans votre espace de noms principal, en fonction de la taille et de la complexité, vous pouvez ouvrir des sous-espaces de noms. C'est là que les noms signifient clairement quelque chose dans un contexte, et les mêmes noms peuvent être utilisés dans un contexte différent.

En particulier, si vous avez un nom de sondage générique comme FileInfo qui signifie quelque chose de particulier dans un contexte, placez-le dans un espace de noms.

Vous pouvez également utiliser une classe pour cela, bien qu'une classe ne soit pas extensible, vous ne pouvez donc pas ajouter de nouvelles déclarations à la classe sans modifier son en-tête.

9
CashCow

Les espaces de noms ne sont pas un concept de module, donc je ne les utiliserais que là où des conflits de noms pourraient se produire.

3
Brainlag

J'aime les espaces de noms profonds (ce qui signifie généralement trois niveaux).

  • J'ai le nom de l'entreprise.
  • app/util/lib/etc
  • Nom du projet/ou package selon le cas

Selon la situation, je peux avoir un niveau supplémentaire

  • détails (détails d'implémentation spécifiques à la plateforme)
  • utils (objet utilitaire qui n'a pas encore été déplacé vers l'utilitaire général).
  • tout ce dont j'ai besoin.
1
Martin York

Java a des espaces de noms, ils ne sont pas vraiment appelés ainsi. Dans javax.swing.*javax est un espace de noms et swing est un sous-espace de noms. Je n'ai pas lu le livre pour savoir ce qu'il dit sur les packages Java, mais les mêmes principes s'appliqueraient à peu près directement aux espaces de noms dans n'importe quelle langue.

Une bonne heuristique est que vous utilisez un espace de noms lorsque vous voulez taper le même préfixe pour les classes encore et encore. Par exemple, j'ai récemment écrit quelques classes appelées OmciAttribute, OmciAlarm, OmciMe, etc. et j'ai réalisé que je devais séparer Omci dans son propre espace de noms.

1
Karl Bielefeldt