it-swarm.it

Best practice per l'utilizzo di spazi dei nomi in C ++

Ho letto lo zio Bob codice pulito qualche mese fa, e ha avuto un profondo impatto sul modo in cui scrivo il codice. Anche se sembrava che stesse ripetendo cose che ogni programmatore dovrebbe sapere, metterle tutte insieme e metterle in pratica si traduce in un codice molto più pulito. In particolare, ho trovato la scomposizione di grandi funzioni in molte minuscole funzioni e la scomposizione di grandi classi in molte minuscole classi sono incredibilmente utili.

Ora per la domanda. Gli esempi del libro sono tutti in Java, mentre ho lavorato in C++ negli ultimi anni. In che modo le idee in Clean Code si estenderebbero all'uso di spazi dei nomi, che non esistono in Java? (Sì, conosco i Java, ma non è proprio lo stesso.)

Ha senso applicare l'idea di creare molte piccole entità, ognuna con una chiara responsabilità, agli spazi dei nomi? Un piccolo gruppo di classi correlate dovrebbe sempre essere racchiuso in uno spazio dei nomi? È questo il modo di gestire la complessità di avere molte piccole classi o il costo della gestione di molti spazi dei nomi sarebbe proibitivo?

Modifica: la mia domanda ha una risposta in questo voce di Wikipedia sui principi del pacchetto .

39
Dima

(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 di nuovo 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 sono "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'uso 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.

23
Fred Nurk

Dovresti avere uno spazio dei nomi principale per tutto il codice. Questo lo distingue dal codice esterno per quanto riguarda gli spazi dei nomi.

All'interno dello spazio dei nomi principale, a seconda delle dimensioni e della complessità, è possibile aprire spazi dei nomi secondari. È qui che i nomi significano chiaramente qualcosa in un contesto e gli stessi nomi potrebbero essere usati in un contesto diverso.

In particolare se hai un nome dal suono generico come FileInfo che significa qualcosa di particolare in un contesto, inseriscilo in uno spazio dei nomi.

Puoi anche usare una classe per questo, sebbene una classe non sia estensibile, quindi non puoi aggiungere nuove dichiarazioni alla classe senza modificarne l'intestazione.

9
CashCow

Namespace non è un concetto di modulo, quindi li userei solo dove potrebbero verificarsi conflitti di nomi.

3
Brainlag

Mi piacciono gli spazi dei nomi profondi (che di solito significa tre livelli).

  • Ho il nome dell'azienda.
  • app/util/lib/etc
  • Nome del progetto/o pacchetto come appropriato

A seconda della situazione, potrei avere un livello in più

  • dettagli (dettagli di implementazione specifici della piattaforma)
  • utils (oggetto utility che non è stato ancora spostato in utility generale).
  • qualunque cosa mi serva.
1
Martin York

Java ha spazi dei nomi, non sono proprio così chiamati. In javax.swing.*javax è uno spazio dei nomi e swing è uno spazio dei nomi secondari. Non ho letto il libro per sapere cosa dice Java, ma gli stessi principi si applicano praticamente direttamente agli spazi dei nomi in qualsiasi lingua.

Una buona euristica è che usi uno spazio dei nomi quando ti ritrovi a voler scrivere più volte lo stesso prefisso per le classi. Ad esempio, di recente ho scritto alcune classi chiamate OmciAttribute, OmciAlarm, OmciMe, ecc. E ho capito che dovevo dividere Omci nel suo spazio dei nomi.

1
Karl Bielefeldt