it-swarm.dev

Best Practices für die Verwendung von Namespaces in C ++

Ich habe vor ein paar Monaten Onkel Bobs Clean Code gelesen und es hat einen tiefgreifenden Einfluss auf die Art und Weise, wie ich Code schreibe. Selbst wenn es so aussah, als würde er Dinge wiederholen, die jeder Programmierer wissen sollte, führt das Zusammenfügen und Umsetzen von Dingen zu einem viel saubereren Code. Insbesondere fand ich es unglaublich nützlich, große Funktionen in viele kleine Funktionen aufzuteilen und große Klassen in viele kleine Klassen aufzuteilen.

Nun zur Frage. Die Beispiele des Buches sind alle in Java, während ich in den letzten Jahren in C++ gearbeitet habe. Wie würden sich die Ideen in Clean Code auf die Verwendung von Namespaces erstrecken, die in Java nicht existieren? (Ja, ich kenne die Java -Pakete, aber es ist nicht wirklich dasselbe.)

Ist es sinnvoll, die Idee, viele winzige Einheiten mit jeweils klar definierter Verantwortung zu erstellen, auf Namespaces anzuwenden? Sollte eine kleine Gruppe verwandter Klassen immer in einen Namespace eingeschlossen werden? Ist dies der Weg, um die Komplexität vieler kleiner Klassen zu verwalten, oder wären die Kosten für die Verwaltung vieler Namespaces unerschwinglich?

Bearbeiten: Meine Frage wird in diesem Wikipedia-Eintrag über Paketprinzipien beantwortet.

39
Dima

(Ich habe Clean Code nicht gelesen und kenne nicht viel Java.)

Ist es sinnvoll, die Idee, viele winzige Einheiten mit jeweils klar definierter Verantwortung zu erstellen, auf Namespaces anzuwenden?

Ja, genau wie beim Refactoring in mehrere Klassen und mehrere Funktionen.

Sollte eine kleine Gruppe verwandter Klassen immer in einen Namespace eingeschlossen werden?

Ohne tatsächlich zu antworten: Ja, Sie sollten mindestens einen Namespace der obersten Ebene verwenden. Dies kann auf Projekt, Organisation oder was auch immer basieren, aber die Verwendung weniger globaler Namen reduziert Namenskonflikte. Ein einzelner Namespace zum Gruppieren aller anderen Elemente führt nur einen globalen Namen ein. (Ausgenommen externe "C" -Funktionen, aber das liegt an der C-Interoperabilität und betrifft nur andere externe "C" -Funktionen.)

Sollte eine kleine Gruppe verwandter Klassen in einen ihnen zugewiesenen Namespace eingeschlossen werden? Wahrscheinlich. Insbesondere wenn Sie ein gemeinsames Präfix für diese Klassen verwenden - FrobberThing, FrobberThang, FrobberDoohickey - sollten Sie einen Namespace in Betracht ziehen - frobber :: Thing und so weiter. Dies würde sich immer noch unter Ihrem Root-Namespace oder einem anderen Namespace befinden, wenn diese Teil eines größeren Projekts sind.

Ist dies der Weg, um die Komplexität vieler kleiner Klassen zu verwalten, oder wären die Kosten für die Verwaltung vieler Namespaces unerschwinglich?

Anhand des obigen Beispiels für Präfixnamen ist es nicht schwieriger, frobber :: Thing zu verwalten als FrobberThing. Mit einigen Tools wie Dokumentation und Code-Vervollständigung kann es sogar einfacher sein. Es gibt einen Unterschied zu ADL, aber dies kann zu Ihren Gunsten wirken: Weniger Namen in zugeordneten Namespaces erleichtern das Herausfinden von ADL, und Sie können Deklarationen verwenden, um bestimmte Namen in den einen oder anderen Namespace einzufügen.

Mit Namespace-Aliasnamen können Sie einen kürzeren Namen für einen längeren Namespace in einem bestimmten Kontext verwenden, was wiederum eine einfachere Verwendung ermöglicht:

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

Betrachten Sie Boost, das einen einzelnen Root-Namespace, Boost und dann viele Subnamespaces - boost :: asio, boost :: io, boost :: filesystem, boost :: tuples usw. - für verschiedene Bibliotheken hat. Einige Namen werden "befördert" in den Root-Namespace:

Alle Definitionen befinden sich in Namespace :: Boost :: Tuples, aber die gebräuchlichsten Namen werden mithilfe von Deklarationen in Namespace :: Boost verschoben. Diese Namen sind: Tuple, make_Tuple, tie and get. Außerdem werden ref und cref direkt unter dem :: boost-Namespace definiert.

Der größte Unterschied zu Sprachen mit "echten" Modulen besteht darin, wie häufig eine flachere Struktur verwendet wird. Dies geschieht meistens, weil dies so funktioniert, es sei denn, Sie unternehmen zusätzliche, spezifische Anstrengungen, um verschachtelte Namen zu definieren.

23
Fred Nurk

Sie sollten einen Master-Namespace für Ihren gesamten Code haben. Dies unterscheidet es von externem Code in Bezug auf Namespaces.

In Ihrem Master-Namespace können Sie abhängig von der Größe und Komplexität Unter-Namespaces öffnen. Hier bedeuten Namen eindeutig etwas in einem Kontext, und dieselben Namen können in einem anderen Kontext verwendet werden.

Insbesondere wenn Sie einen generisch klingenden Namen wie FileInfo haben, der etwas Bestimmtes in einem Kontext bedeutet, fügen Sie ihn in einen Namespace ein.

Sie können hierfür auch eine Klasse verwenden, obwohl eine Klasse nicht erweiterbar ist, sodass Sie der Klasse keine neuen Deklarationen hinzufügen können, ohne ihren Header zu ändern.

9
CashCow

Namespaces sind kein Modulkonzept, daher würde ich sie nur dort verwenden, wo Namenskonflikte auftreten können.

3
Brainlag

Ich mag tiefe Namespaces (was normalerweise drei Ebenen bedeutet).

  • Ich habe den Firmennamen.
  • app/util/lib/etc.
  • Projektname/oder Paket entsprechend

Je nach Situation kann ich eine weitere Ebene haben

  • details (Plattformspezifische Implementierungsdetails)
  • utils (Dienstprogrammobjekt, das noch nicht in das allgemeine Dienstprogramm verschoben wurde).
  • was auch immer ich brauche.
1
Martin York

Java hat Namespaces, die werden einfach nicht so genannt. Im javax.swing.*javax ist ein Namespace und swing ist ein Sub-Namespace. Ich habe das Buch nicht gelesen, um zu wissen, was es über Java Pakete) sagt, aber die gleichen Prinzipien würden ziemlich direkt auf Namespaces in jeder Sprache angewendet.

Eine gute Heuristik ist, dass Sie einen Namespace verwenden, wenn Sie immer wieder dasselbe Präfix für Klassen eingeben möchten. Zum Beispiel habe ich kürzlich einige Klassen mit den Namen OmciAttribute, OmciAlarm, OmciMe usw. geschrieben und festgestellt, dass ich Omci in einen eigenen Namespace aufteilen muss.

1
Karl Bielefeldt