Praktik terbaik untuk menggunakan ruang nama di C ++ [ditutup]

38

Saya telah membaca Kode Bersih Paman Bob beberapa bulan yang lalu, dan itu berdampak besar pada cara saya menulis kode. Bahkan jika sepertinya dia mengulangi hal-hal yang harus diketahui oleh setiap programmer, menggabungkan semuanya dan mempraktikkannya menghasilkan kode yang jauh lebih bersih. Secara khusus, saya menemukan memecah fungsi besar menjadi banyak fungsi kecil, dan memecah kelas besar menjadi banyak kelas kecil sangat berguna.

Sekarang untuk pertanyaannya. Contoh-contoh buku semuanya di Jawa, sementara saya telah bekerja di C ++ selama beberapa tahun terakhir. Bagaimana gagasan dalam Kode Bersih meluas ke penggunaan ruang nama, yang tidak ada di Jawa? (Ya, saya tahu tentang paket Java, tetapi sebenarnya tidak sama.)

Apakah masuk akal untuk menerapkan gagasan menciptakan banyak entitas kecil, masing-masing dengan tanggung jawab yang jelas, untuk ruang nama? Haruskah sekelompok kecil kelas terkait selalu dibungkus dalam namespace? Apakah ini cara untuk mengelola kompleksitas memiliki banyak kelas kecil, atau apakah biaya mengelola banyak ruang nama akan menjadi penghalang?

Sunting: Pertanyaan saya dijawab dalam entri Wikipedia ini tentang Prinsip Paket .

Dima
sumber
7
Contoh lain dari pertanyaan pengembang yang baik dan dunia nyata ditutup . Jika ini bukan situs stackexchange untuk bertanya tentang praktik terbaik pengembang, apakah itu?
Sam Goldberg
@ SamGoldberg: semakin baik. Saya menemukan jawaban yang bagus untuk pertanyaan ini di sini: en.wikipedia.org/wiki/Package_Principles . Saya memposting jawaban ini, dan seorang moderator menghapusnya, karena saya cukup memposting tautan dan tidak punya waktu untuk menyalin / menempel konten.
Dima
1
Saya pikir satu-satunya kritik saya atas pertanyaan itu adalah, alih-alih mengajukan beberapa pertanyaan di akhir, cobalah untuk meringkasnya menjadi satu pertanyaan tunggal, misalnya "apa yang harus menjadi kriteria untuk menentukan apakah item harus berada dalam ruang nama yang sama atau ruang nama yang berbeda? ".
Sam Goldberg

Jawaban:

22

(Saya belum membaca Kode Bersih dan tidak tahu banyak tentang Java.)

Apakah masuk akal untuk menerapkan gagasan menciptakan banyak entitas kecil, masing-masing dengan tanggung jawab yang jelas, untuk ruang nama?

Ya, seperti halnya dengan refactoring ke dalam beberapa kelas dan beberapa fungsi.

Haruskah sekelompok kecil kelas terkait selalu dibungkus dalam namespace?

Tanpa benar-benar menjawab: ya, Anda setidaknya harus menggunakan satu namespace tingkat atas. Ini dapat didasarkan pada proyek, organisasi, atau apa pun yang Anda suka, tetapi menggunakan beberapa nama global akan mengurangi konflik nama. Satu namespace untuk mengelompokkan semua yang lain di bawahnya hanya memperkenalkan satu nama global. (Kecuali fungsi "C" eksternal, tapi itu karena interoperabilitas C dan hanya mempengaruhi fungsi "C" eksternal lainnya.)

Haruskah sekelompok kecil kelas terkait dibungkus dalam namespace yang didedikasikan untuk mereka? Mungkin. Terutama jika Anda menemukan diri Anda menggunakan awalan umum pada kelas-kelas tersebut - FrobberThing, FrobberThang, FrobberDoohickey - Anda harus mempertimbangkan namespace - frobber :: Thing dan sebagainya. Ini masih berada di bawah namespace root Anda atau namespace lain jika mereka merupakan bagian dari proyek yang lebih besar.

Apakah ini cara untuk mengelola kompleksitas memiliki banyak kelas kecil, atau apakah biaya mengelola banyak ruang nama akan menjadi penghalang?

Mengambil contoh di atas nama awalan, tidak sulit untuk mengelola frobber :: Thing daripada FrobberThing. Bahkan mungkin lebih mudah dengan beberapa alat, seperti dokumentasi dan penyelesaian kode. Ada perbedaan dengan ADL, tetapi ini dapat menguntungkan Anda: lebih sedikit nama dalam ruang nama terkait membuat ADL lebih mudah untuk diketahui, dan Anda dapat menggunakan deklarasi untuk menyuntikkan nama tertentu ke dalam satu namespace atau lainnya.

Alias ​​Namespace memungkinkan Anda menggunakan nama yang lebih pendek untuk namespace yang lebih panjang dalam konteks tertentu, yang sekali lagi memungkinkan penggunaan yang lebih mudah:

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

Pertimbangkan Boost, yang memiliki ruang nama root tunggal, boost, dan kemudian banyak ruangnama - boost :: asio, boost :: io, boost :: filesystem, boost :: tuple, dll. - untuk berbagai perpustakaan. Beberapa nama "dipromosikan" ke root namespace:

Semua definisi ada di namespace :: boost :: tuple, tetapi nama yang paling umum diangkat ke namespace :: boost dengan menggunakan deklarasi. Nama-nama ini adalah: tuple, make_tuple, tie and get. Selanjutnya, ref dan cref didefinisikan langsung di bawah :: boost namespace.

Perbedaan terbesar dari bahasa dengan modul "nyata" adalah seberapa umum menggunakan struktur yang lebih datar, yang sebagian besar terjadi karena itulah cara kerjanya kecuali jika Anda mengambil upaya ekstra dan spesifik untuk mendefinisikan nama bersarang.

Fred Nurk
sumber
+1 @Fred Nurk untuk analisis lengkap alih-alih satu jawaban baris. Anda tidak harus membaca buku untuk mengetahui pertanyaannya. Utas komentar ini memaparkan konsep dan perbedaan yang mungkin dimiliki oleh seorang C ++ dan seorang programmer Java pada buku ini. Komentar Clean Code di Amazon
Marlon
8

Anda harus memiliki satu ruang nama utama untuk semua kode Anda. Ini membedakannya dari kode eksternal berkaitan dengan ruang nama.

Di dalam master namespace Anda, tergantung pada ukuran dan kompleksitasnya, Anda dapat membuka sub-namespaces. Di sinilah nama jelas berarti sesuatu dalam konteks, dan nama yang sama dapat digunakan dalam konteks yang berbeda.

Khususnya jika Anda memiliki nama yang terdengar umum seperti FileInfo yang berarti sesuatu yang khusus dalam konteks, letakkan di namespace.

Anda juga dapat menggunakan kelas untuk ini, meskipun kelas tidak dapat diperluas sehingga Anda tidak dapat menambahkan deklarasi baru ke kelas tanpa memodifikasi headernya.

Uang tunai
sumber
3

Namespace bukan konsep Modul jadi saya akan menggunakannya hanya di mana konflik nama bisa terjadi.

Brainlag
sumber
4
Tidak yakin apa yang kamu maksud. Mengapa satu set kelas terkait yang dibungkus dalam namespace tidak menjadi modul?
Dima
Tidak ada batasan dalam namespace. Dalam sebuah modul, Anda dapat mengatakan bahwa kelas, fungsi, atau variabel tertentu hanya dapat diakses dari dalam modul. Dalam namespace ini tidak mungkin itu hanya awalan untuk nama.
Brainlag
3
Sepertinya kita tidak setuju dengan definisi modul . Bagi saya apa pun yang mengelompokkan entitas terkait bersama-sama dan memiliki nama deskriptif adalah modul, terlepas dari layu atau tidaknya, menyediakan enkapsulasi.
Dima
3
Pembatasan akses bersifat ortogonal ke modul. Bahkan, Anda memiliki sistem yang sukses seperti Python yang pastinya lebih "mirip modul" daripada ruang nama C ++, tetapi tidak memaksakan batasan akses sama sekali.
Fred Nurk
Saya percaya ini adalah salah satu praktik terbaik yang tercantum di buku
Raphael
1

Java memiliki ruang nama, mereka tidak benar-benar menyebutnya. In javax.swing.* javaxadalah namespace dan swingmerupakan sub-namespace. Saya belum membaca buku ini untuk mengetahui apa yang dikatakannya tentang paket java, tetapi prinsip yang sama akan berlaku cukup langsung ke ruang nama dalam bahasa apa pun.

Heuristik yang baik adalah Anda menggunakan namespace ketika Anda menemukan diri Anda ingin mengetikkan awalan yang sama untuk kelas berulang kali. Sebagai contoh, saya baru-baru ini menulis beberapa kelas yang disebut OmciAttribute, OmciAlarm, OmciMe, dll. Dan menyadari bahwa saya perlu memecah Omci ke dalam namespace-nya sendiri.

Karl Bielefeldt
sumber
1

Saya suka ruang nama yang dalam (yang biasanya berarti tiga tingkat).

  • Saya punya nama perusahaan.
  • app / util / lib / etc
  • Nama Proyek / atau Paket yang sesuai

Tergantung pada situasi saya mungkin memiliki satu level lagi

  • detail (Detail implementasi spesifik platform)
  • utils (objek utilitas yang belum dipindahkan ke utilitas umum).
  • apapun yang saya butuhkan.
Martin York
sumber