Dalam proyek C ++ saya, saya punya dua kelas, Particle
dan Contact
. Di Particle
kelas, saya memiliki variabel anggota std::vector<Contact> contacts
yang berisi semua kontak dari suatu Particle
objek, dan fungsi anggota yang sesuai getContacts()
dan addContact(Contact cont)
. Jadi, dalam "Particle.h", saya memasukkan "Contact.h".
Di Contact
kelas, saya ingin menambahkan kode ke konstruktor untuk Contact
panggilan itu Particle::addContact(Contact cont)
, sehingga contacts
diperbarui untuk kedua Particle
objek di mana Contact
objek ditambahkan. Jadi, saya harus memasukkan "Particle.h" dalam "Contact.cpp".
Pertanyaan saya adalah apakah ini dapat diterima / praktik pengkodean yang baik dan, jika tidak, apa yang akan menjadi cara yang lebih baik untuk mengimplementasikan apa yang saya coba capai (sederhananya, secara otomatis memperbarui daftar kontak untuk partikel tertentu setiap kali kontak baru dibuat).
Kelas-kelas ini akan diikat bersama oleh Network
kelas yang akan memiliki N partikel ( std::vector<Particle> particles
) dan kontak Nc ( std::vector<Contact> contacts
). Tapi saya ingin dapat memiliki fungsi seperti particles[0].getContacts()
- apakah boleh memiliki fungsi seperti itu di Particle
kelas dalam kasus ini, atau apakah ada asosiasi "struktur" yang lebih baik di C ++ untuk tujuan ini (dari dua kelas terkait yang digunakan di kelas lain) .
Saya mungkin perlu perubahan perspektif di sini tentang bagaimana saya mendekati ini. Karena dua kelas dihubungkan oleh Network
objek kelas, apakah itu kode / kelas organisasi yang khas untuk memiliki informasi konektivitas sepenuhnya dikendalikan oleh Network
objek (di mana objek partikel tidak harus menyadari kontaknya dan, akibatnya, seharusnya tidak memiliki getContacts()
anggota fungsi). Kemudian, untuk mengetahui kontak apa yang dimiliki partikel tertentu, saya perlu mendapatkan informasi itu melalui Network
objek (misalnya, menggunakan network.getContacts(Particle particle)
).
Apakah itu kurang khas (bahkan mungkin berkecil hati) desain kelas C ++ untuk objek Partikel untuk memiliki pengetahuan itu, juga (yaitu, memiliki beberapa cara untuk mengakses informasi itu - baik melalui objek Jaringan atau objek Partikel, mana yang tampaknya lebih nyaman )?
sumber
Network
objek kelas yang berisiParticle
objek danContact
objek. Dengan pengetahuan dasar itu, saya kemudian dapat mencoba menilai apakah cocok atau tidak dengan kebutuhan spesifik saya, yang masih dieksplorasi / dikembangkan saat saya mengikuti proyek ini.Jawaban:
Ada dua bagian dalam pertanyaan Anda.
Bagian pertama adalah organisasi file header C ++ dan file sumber. Ini dipecahkan dengan menggunakan deklarasi maju dan pemisahan deklarasi kelas (meletakkannya di file header) dan metode tubuh (meletakkannya di file sumber). Lebih jauh lagi, dalam beberapa kasus seseorang dapat menerapkan idiom Pimpl ("pointer ke implementasi") untuk menyelesaikan kasus yang lebih sulit. Gunakan pointer kepemilikan bersama (
shared_ptr
), pointer kepemilikan tunggal (unique_ptr
), dan pointer tidak memiliki (pointer mentah, yaitu "tanda bintang") sesuai dengan praktik terbaik.Bagian kedua adalah bagaimana memodelkan objek yang saling terkait dalam bentuk grafik . Grafik umum yang bukan DAG (grafik asiklik langsung) tidak memiliki cara alami untuk mengekspresikan kepemilikan seperti pohon. Sebagai gantinya, semua node dan koneksi adalah metadata yang dimiliki oleh objek grafik tunggal. Dalam hal ini, tidak mungkin untuk memodelkan hubungan simpul-koneksi sebagai agregasi. Node tidak memiliki "koneksi"; koneksi tidak "memiliki" node. Sebaliknya, mereka adalah asosiasi, dan kedua node dan koneksi "dimiliki oleh" grafik. Grafik menyediakan metode kueri dan manipulasi yang beroperasi pada node dan koneksi.
sumber
particles[0].getContacts()
- apakah Anda menyarankan dalam paragraf terakhir Anda bahwa saya seharusnya tidak memiliki fungsi seperti itu diParticle
kelas, atau bahwa struktur saat ini baik-baik saja karena mereka terkait / terkait secara inheren melaluiNetwork
? Apakah ada "struktur" asosiasi yang lebih baik dalam C ++ dalam kasus ini?network.particle[p]
akan memiliki yang sesuainetwork.contacts[p]
dengan indeks kontaknya. Kalau tidak, Jaringan dan Partikel entah bagaimana melacak informasi yang sama.Particle
objek tidak harus mengetahui kontaknya (jadi saya tidak boleh memilikigetContacts()
fungsi anggota), dan bahwa informasi itu seharusnya hanya berasal dari dalamNetwork
objek? Apakah ini akan menjadi desain kelas C ++ yang buruk untukParticle
objek yang memiliki pengetahuan itu (yaitu, memiliki beberapa cara untuk mengakses informasi itu - baik melaluiNetwork
objek atauParticle
objek, mana yang lebih nyaman)? Yang terakhir tampaknya lebih masuk akal bagi saya, tetapi mungkin saya perlu mengubah perspektif saya tentang ini.Particle
mengetahui apa-apa tentangContact
s atauNetwork
s adalah ia mengikat Anda dengan cara tertentu untuk mewakili hubungan itu. Ketiga kelas mungkin harus setuju. Jika bukan satuNetwork
-satunya yang tahu atau peduli, itu hanya satu kelas yang perlu diubah jika Anda memutuskan representasi lain lebih baik.Particle
danContact
harus benar-benar terpisah, dan hubungan di antara mereka ditentukan olehNetwork
objek. Hanya untuk benar-benar yakin, inilah (mungkin) yang dimaksud dengan @rwong ketika ia menulis, "baik node maupun koneksi" dimiliki oleh "grafik. Grafik menyediakan metode kueri dan manipulasi yang beroperasi pada node dan koneksi." , Baik?Jika saya membuat Anda benar, objek kontak yang sama milik lebih dari satu objek partikel, karena itu mewakili semacam kontak fisik antara dua atau lebih partikel, kan?
Jadi hal pertama yang menurut saya patut dipertanyakan adalah mengapa
Particle
memiliki variabel anggotastd::vector<Contact>
? Seharusnya astd::vector<Contact*>
ataustd::vector<std::shared_ptr<Contact> >
sebaliknya.addContact
maka harus memiliki tanda tangan berbeda sepertiaddContact(Contact *cont)
atauaddContact(std::shared_ptr<Contact> cont)
sebagai gantinya.Ini membuatnya tidak perlu untuk memasukkan "Contact.h" dalam "Particle.h", sebuah deklarasi maju
class Contact
dalam "Particle.h", dan menyertakan "Contact.h" dalam "Particle.cpp" sudah cukup.Lalu pertanyaan tentang konstruktor. Anda menginginkan sesuatu seperti
Baik? Desain ini ok, asalkan program Anda selalu mengetahui partikel terkait pada titik waktu ketika objek kontak harus dibuat.
Catatan, jika Anda pergi
std::vector<Contact*>
rute, Anda harus menginvestasikan beberapa pemikiran tentang masa hidup dan kepemilikanContact
objek. Tidak ada partikel "memiliki" kontaknya, kontak mungkin harus dihapus hanya jika keduaParticle
objek terkait dihancurkan.std::shared_ptr<Contact>
Sebaliknya, menggunakan akan menyelesaikan masalah ini untuk Anda secara otomatis. Atau Anda membiarkan objek "konteks sekitarnya" mengambil kepemilikan partikel dan kontak (seperti yang disarankan oleh @rwong), dan mengelola masa pakainya.sumber
addContact(const std::shared_ptr<Contact> &cont)
atasaddContact(std::shared_ptr<Contact> cont)
?move
paradigmaparticle1.getContacts()
danparticle2.getContacts()
mengirimkanContact
objek yang sama yang mewakili kontak fisik antaraparticle1
danparticle2
, dan bukan dua objek yang berbeda. Tentu saja, seseorang dapat mencoba mendesain sistem dengan cara yang tidak masalah jika ada duaContact
objek yang tersedia sekaligus mewakili kontak fisik yang sama. Ini akan melibatkan untuk membuatContact
kekekalan, tetapi apakah Anda yakin ini yang Anda inginkan?Ya, apa yang Anda gambarkan adalah cara yang dapat diterima untuk memastikan bahwa setiap
Contact
instance ada dalam daftar kontak aParticle
.sumber
Apa yang Anda lakukan benar.
Cara lain ... Jika tujuannya adalah untuk memastikan bahwa setiap orang
Contact
ada dalam daftar, maka Anda dapat:Contact
(konstruktor pribadi),Particle
kelas,Particle
kelas temanContact
,Particle
membuat metode pabrik yang membuat aContact
Maka Anda tidak harus menyertakan
particle.h
dicontact
sumber
Network
kelas, apakah itu mengubah struktur yang disarankan, atau apakah masih sama?Opsi lain yang mungkin Anda pertimbangkan adalah membuat konstruktor Kontak yang menerima referensi Partikel templated. Ini akan memungkinkan Kontak untuk menambahkan dirinya sendiri ke wadah apa pun yang mengimplementasikan
addContact(Contact)
.sumber