(Non ho letto Clean Code e non conosco molto Java.)
Ha senso applicare l'idea di creare molte piccole entità, ognuna con una chiara responsabilità, agli spazi dei nomi?
Sì, proprio come accade con il refactoring in più classi e più funzioni.
Un piccolo gruppo di classi correlate dovrebbe sempre essere racchiuso in uno spazio dei nomi?
Senza effettivamente rispondere: sì, dovresti almeno usare uno spazio dei nomi di livello superiore. Questo può essere basato su progetto, organizzazione o qualunque cosa ti piaccia, ma l'uso di pochi nomi globali ridurrà i conflitti di nomi. Un singolo spazio dei nomi per raggruppare tutto il resto al suo interno introduce un solo nome globale. (Ad eccezione delle funzioni "C" esterne, ma ciò è dovuto all'interoperabilità C e influisce solo su altre funzioni "C" esterne.)
Un piccolo gruppo di classi correlate dovrebbe essere racchiuso in uno spazio dei nomi a loro dedicato? Probabilmente. Soprattutto se ti ritrovi a usare un prefisso comune su quelle classi - FrobberThing, FrobberThang, FrobberDoohickey - dovresti considerare uno spazio dei nomi - frobber :: Thing e così via. Questo sarebbe ancora sotto il tuo spazio dei nomi di root o un altro spazio dei nomi se fanno parte di un progetto più grande.
È questo il modo di gestire la complessità di avere molte piccole classi o il costo della gestione di molti spazi dei nomi sarebbe proibitivo?
Prendendo l'esempio sopra di nomi prefissati, non è più difficile gestire frobber :: Thing che FrobberThing. Potrebbe anche essere più facile con alcuni strumenti, come la documentazione e il completamento del codice. C'è una differenza con ADL, ma questo può funzionare a tuo favore: un minor numero di nomi negli spazi dei nomi associati rende ADL più semplice da capire e puoi usare dichiarazioni per iniettare nomi specifici in uno spazio dei nomi o in un altro.
Gli alias dello spazio dei nomi consentono di utilizzare un nome più breve per uno spazio dei nomi più lungo in un contesto specifico, che consente nuovamente un utilizzo più semplice:
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.
}
Considera Boost, che ha un unico spazio dei nomi di root, boost e quindi molti spazi dei nomi secondari - boost :: asio, boost :: io, boost :: filesystem, boost :: tuples, ecc. - per varie librerie. Alcuni nomi vengono "promossi" nello spazio dei nomi radice:
Tutte le definizioni sono nello spazio dei nomi :: boost :: tuple, ma i nomi più comuni vengono portati nello spazio dei nomi :: boost con l'utilizzo delle dichiarazioni. Questi nomi sono: tuple, make_tuple, tie and get. Inoltre, ref e cref sono definiti direttamente nello spazio dei nomi :: boost.
La più grande differenza rispetto alle lingue con moduli "reali" è quanto sia comune usare una struttura più piatta, cosa che accade principalmente perché è così che funziona a meno che non si faccia uno sforzo aggiuntivo e specifico per definire i nomi nidificati.