(Ich habe Clean Code nicht gelesen und kenne nicht viel Java.)
Ist es sinnvoll, die Idee, viele kleine Einheiten mit jeweils klar definierter Verantwortung zu erstellen, auf Namespaces anzuwenden?
Ja, genau wie beim Refactoring in mehrere Klassen und Funktionen.
Soll eine kleine Gruppe zusammengehöriger 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 verringert Namenskonflikte. Ein einziger Namespace, in dem alle anderen Elemente gruppiert werden, führt nur einen globalen Namen ein. (Ausgenommen externe "C" -Funktionen, dies liegt jedoch an der C-Interoperabilität und wirkt sich nur auf andere externe "C" -Funktionen aus.)
Sollte eine kleine Gruppe verwandter Klassen in einen ihnen gewidmeten Namespace eingeschlossen werden? Wahrscheinlich. Besonders wenn Sie feststellen, dass 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 Stamm-Namespace oder einem anderen Namespace befinden, wenn sie Teil eines größeren Projekts sind.
Ist dies der Weg, um die Komplexität von vielen kleinen 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 als FrobberThing zu verwalten. 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 funktionieren: Weniger Namen in zugeordneten Namespaces vereinfachen das Herausfinden von ADL, und Sie können mithilfe von Deklarationen bestimmte Namen in den einen oder anderen Namespace einfü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 einzigen Root-Namespace, boost und dann viele Subnamespaces - boost :: asio, boost :: io, boost :: filesystem, boost :: tuples usw. - für verschiedene Bibliotheken hat. Einige Namen werden in den Root-Namespace "befördert" :
Alle Definitionen befinden sich im Namespace :: boost :: tuples, die gebräuchlichsten Namen werden jedoch mithilfe von Deklarationen in den Namespace :: boost angehoben. Diese Namen sind: tuple, make_tuple, tie and get. Außerdem werden ref und cref direkt unter dem Namespace :: boost 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 nehmen zusätzliche, spezifische Anstrengungen in Kauf, um verschachtelte Namen zu definieren.