Best practice per l'utilizzo degli spazi dei nomi in C ++ [chiuso]


38

Ho letto il codice pulito dello zio Bob alcuni mesi 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 pacchetti 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 trova risposta in questa voce di Wikipedia sui principi del pacchetto .


7
Un altro esempio di una domanda per sviluppatori valida e reale è stata chiusa . Se questo non è il sito stackexchange per chiedere le migliori pratiche degli sviluppatori, che cos'è?
Sam Goldberg,

@SamGoldberg: migliora. Ho trovato una buona risposta a questa domanda qui: en.wikipedia.org/wiki/Package_Principles . Ho pubblicato questa risposta e un moderatore l'ha cancellata, perché ho semplicemente pubblicato il link e non ho avuto il tempo di copiare / incollare il contenuto.
Dima,

1
Penso che la mia unica critica alla domanda sarebbe, invece di porre più domande alla fine, provare a sintetizzarla in un'unica domanda, ad esempio "quali dovrebbero essere i criteri per determinare se gli elementi dovrebbero essere nello stesso spazio dei nomi o spazi dei nomi diversi? ".
Sam Goldberg,

Risposte:


22

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


+1 @Fred Nurk per l'analisi completa invece delle risposte a una riga. Non devi leggere il libro per sapere di cosa tratta la domanda. Questo thread di commenti espone i concetti e le differenze che un programmatore C ++ e Java potrebbe avere su questo libro. Commento su Clean Code in Amazon
Marlon,

8

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.


3

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


4
Non sono sicuro cosa intendi. Perché un insieme di classi correlate racchiuse in uno spazio dei nomi non dovrebbe essere un modulo?
Dima,

Non ci sono restrizioni nello spazio dei nomi. In un modulo puoi dire che una determinata classe, funzione o variabile è accessibile solo dall'interno del modulo. In uno spazio dei nomi questo non è possibile, è solo un prefisso per il nome.
Brainlag,

3
Sembra che non siamo d'accordo sulla definizione di un modulo . Per me tutto ciò che raggruppa entità correlate e ha un nome descrittivo è un modulo, indipendentemente dal appassimento o meno fornisce l'incapsulamento.
Dima,

3
La restrizione dell'accesso è ortogonale ai moduli. In effetti, hai sistemi di successo come quelli di Python che sono sicuramente più "simili ai moduli" degli spazi dei nomi di C ++, ma non impongono alcuna limitazione di accesso.
Fred Nurk,

Credo che questa sia una delle migliori pratiche elencate nei libri di Scott Meyer
Raphael,

1

Java ha spazi dei nomi, non sono proprio così chiamati. In javax.swing.* javaxè uno spazio dei nomi ed swingè uno spazio dei nomi secondari. Non ho letto il libro per sapere cosa dice sui pacchetti 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

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.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.