Saya telah melihat pertanyaan hebat tentang topik serupa, tetapi tidak ada yang membahas metode khusus ini:
Mengingat bahwa saya memiliki beberapa koleksi entitas game dalam game [XNA Game Studio] saya, dengan banyak entitas yang dimiliki beberapa daftar, saya sedang mempertimbangkan cara saya bisa melacak kapan pun entitas dihancurkan dan menghapusnya dari daftar yang menjadi miliknya .
Banyak metode potensial yang kelihatannya ceroboh / berbelit-belit, tetapi saya teringat akan cara yang pernah saya lihat sebelumnya, alih-alih memiliki banyak koleksi entitas game, Anda malah memiliki koleksi ID entitas game . ID ini dipetakan ke entitas game melalui "database" pusat (mungkin hanya tabel hash).
Jadi, setiap kali ada sedikit kode yang ingin mengakses anggota entitas gim, pertama-tama ia memeriksa apakah masih ada dalam database. Jika tidak, itu dapat bereaksi sesuai.
Apakah ini pendekatan yang bagus? Tampaknya itu akan menghilangkan banyak risiko / kerepotan menyimpan banyak daftar, dengan pengorbanan menjadi biaya pencarian setiap kali Anda ingin mengakses suatu objek.
sumber
Yang telah Anda lakukan adalah memindahkan beban melakukan pemeriksaan dari waktu kehancuran ke waktu penggunaan. Saya tidak akan mengklaim bahwa saya belum pernah melakukan ini sebelumnya, tetapi saya tidak menganggapnya 'terdengar'.
Saya sarankan menggunakan salah satu dari beberapa alternatif yang lebih kuat. Jika jumlah daftar diketahui, Anda bisa lolos hanya dengan menghapus objek dari semua daftar. Itu tidak berbahaya jika objek tidak ada dalam daftar yang diberikan, dan Anda dijamin telah menghapusnya dengan benar.
Jika jumlah daftar tidak diketahui atau tidak praktis maka simpan kembali referensi kepada mereka pada objek. Implementasi khas ini adalah pola pengamat , tetapi Anda mungkin dapat mencapai efek yang sama dengan delegasi, yang memanggil kembali untuk menghapus item dari daftar yang mengandung bila diperlukan.
Atau kadang-kadang Anda tidak benar-benar membutuhkan banyak daftar sama sekali. Seringkali Anda dapat menyimpan objek hanya dalam satu daftar dan menggunakan kueri dinamis untuk menghasilkan koleksi sementara lainnya saat Anda membutuhkannya. misalnya. Alih-alih memiliki daftar terpisah untuk inventaris karakter, Anda bisa menarik semua objek di mana "terbawa" sama dengan karakter saat ini. Ini mungkin terdengar tidak efisien, tetapi cukup baik untuk database relasional dan dapat dioptimalkan dengan pengindeksan yang cerdas.
sumber
Ini tampaknya hanya menjadi contoh yang lebih spesifik dari masalah "bagaimana menghapus objek dari daftar, sementara iterasi melalui itu", yang mudah diselesaikan (iterasi dalam urutan terbalik mungkin merupakan cara paling sederhana untuk daftar gaya array seperti C # 's
List
).Jika suatu entitas akan direferensikan dari beberapa tempat, maka itu harus menjadi tipe referensi . Jadi Anda tidak harus melalui sistem ID yang berbelit-belit - kelas di C # sudah menyediakan tipuan yang diperlukan.
Dan akhirnya - mengapa repot-repot "memeriksa database"? Cukup beri masing-masing entitas
IsDead
bendera dan periksa itu.sumber
IDisposable
pola, yang sangat mirip dengan menandai objek sebagaiIsDead
. Tentunya jika Anda perlu menggabungkan contoh, daripada memilikinya GC, maka strategi yang lebih rumit diperlukan.ObjectDisposedException
(yang umumnya akan "crash" dengan pengecualian tidak tertangani). Dengan memindahkan tanda centang ke objek itu sendiri (alih-alih memeriksa objek secara eksternal), Anda membiarkan objek menentukan sendiri perilaku "aku mati" dan menghilangkan beban pemeriksaan dari penelepon. Untuk tujuan Anda, Anda bisa menerapkanIDisposable
, atau membuatIsDead
bendera Anda sendiri dengan fungsionalitas serupa.Saya sering menggunakan pendekatan ini dalam permainan C # /. NET saya sendiri. Selain manfaat lain (dan bahaya!) Yang dijelaskan di sini, ini juga dapat membantu menghindari masalah serialisasi.
Jika Anda ingin memanfaatkan fasilitas serialisasi biner .NET Framework bawaan, maka menggunakan ID entitas dapat membantu meminimalkan ukuran grafik objek yang ditulis. Secara default, pemformat biner .NET akan mengeluarkan serial seluruh objek grafik di tingkat bidang. Katakanlah saya ingin membuat serial sebuah
Ship
instance. JikaShip
memiliki_owner
bidang referensiPlayer
siapa yang memilikinya, makaPlayer
instance itu akan keluar juga. JikaPlayer
berisi_ships
bidang (dari, katakanlahICollection<Ship>
), maka semua kapal pemain juga akan ditulis, bersama dengan benda lain yang dirujuk di tingkat bidang (secara rekursif). Sangat mudah untuk secara tidak sengaja membuat serial grafik objek yang besar ketika Anda hanya ingin membuat serialisasi satu bagian kecil saja.Sebaliknya, jika saya memiliki
_ownerId
bidang, maka saya bisa menggunakan nilai itu untuk menyelesaikanPlayer
referensi sesuai permintaan. API publik saya bahkan dapat tetap tidak berubah, denganOwner
properti hanya melakukan pencarian.Sementara pencarian berbasis hash umumnya sangat cepat, overhead yang ditambahkan bisa menjadi masalah untuk set entitas yang sangat besar dengan pencarian sering. Jika itu menjadi masalah bagi Anda, Anda bisa menyimpan referensi dengan menggunakan bidang yang tidak diserialisasi. Misalnya, Anda dapat melakukan sesuatu seperti ini:
Tentu saja, pendekatan ini juga dapat membuat serialisasi lebih sulit ketika Anda benar - benar ingin membuat serial objek grafik besar. Dalam hal ini, Anda perlu merancang semacam 'wadah' untuk memastikan bahwa semua benda yang diperlukan disertakan.
sumber
Cara lain untuk menangani pembersihan Anda adalah dengan membalikkan kontrol dan menggunakan objek Disposable. Anda mungkin memiliki faktor yang mengalokasikan entitas Anda, jadi berikan pabrik semua daftar yang harus ditambahkan. Entitas menyimpan referensi ke semua daftar yang merupakan bagian dari, dan mengimplementasikan IDisposable. Dalam metode buang, ia menghapus dirinya sendiri dari semua daftar. Sekarang Anda hanya perlu peduli dengan manajemen daftar di dua tempat: pabrik (pembuatan) dan buang. Menghapus objek sesederhana entity.Dispose ().
Masalah nama vs referensi dalam C # benar-benar hanya penting untuk mengelola komponen atau tipe nilai. Jika Anda memiliki daftar komponen yang ditautkan ke satu entitas, menggunakan bidang ID sebagai kunci hashmap dapat berguna. Jika Anda hanya memiliki daftar entitas, gunakan saja daftar dengan referensi. Referensi C # aman dan mudah digunakan.
Untuk menghapus atau menambahkan item dari daftar, Anda dapat menggunakan Antrian atau sejumlah solusi lain untuk berurusan dengan menambah dan menghapus dari daftar.
sumber