Hindari memiliki metode inisialisasi

12

Saya memiliki kode yang ada ini di mana mereka memiliki kelas dan metode inisialisasi di kelas itu. Diharapkan setelah objek kelas dibuat, mereka perlu memanggil inisialisasi di atasnya.

Alasan mengapa metode inisialisasi ada Objek akan dibuat lebih awal untuk memiliki cakupan global dan kemudian metode inisialisasi dipanggil nanti setelah memuat dll yang tergantung padanya.

Masalah dengan memiliki inisialisasi Kelas sekarang memiliki bool ini diinisialisasi yang perlu diperiksa di setiap metode sebelum melanjutkan dan mengembalikan kesalahan jika tidak diinisialisasi. Sederhananya, itu adalah rasa sakit yang besar.

Salah satu solusi yang mungkin Inisialisasi dalam konstruktor. Hanya memiliki pointer ke objek dalam lingkup global. Buat objek yang sebenarnya setelah dll dimuat.

Masalah dengan solusi di atas Siapa pun yang membuat objek dari kelas ini perlu tahu bahwa itu perlu dibuat hanya setelah dll dimuat atau yang lain itu akan gagal.

Apakah ini dapat diterima?


sumber
Saya pernah mengalami masalah yang sama ketika membuat objek terkait OpenGL yang perlu dipakai sebelum konteks OpenGL ada, tetapi seharusnya memegang objek yang bergantung OpenGL seperti daftar panggilan, tekstur, dll.
3
Pertanyaan bodoh # 1: Mengapa konstruktor objek tidak dapat memuat DLL jika belum dimuat?
John R. Strohm
1
Mohon maaf karena membangkitkan kembali pertanyaan lama, tetapi jika ada yang membaca ini di tahun 2017, gunakan call_oncedi C ++ 11 . Proyek-proyek yang belum menggunakan C ++ 11 harus mempelajari bagaimana call_once diimplementasikan dalam C ++ 11 (fokus pada masalah apa yang dipecahkannya, dan kemudian bagaimana), dan kemudian mengimplementasikannya kembali dalam rasa C ++ mereka (basi). Dibutuhkan sinkronisasi primitif multi-utas yang aman, yang kondisinya perlu diinisialisasi secara statis (dengan nilai konstan). Perhatikan bahwa kompiler pra-C ++ 11 mungkin memiliki keistimewaan lain yang perlu dipenuhi.
rwong

Jawaban:

7

Kedengarannya seperti pekerjaan untuk proxy virtual.

Anda bisa membuat proxy virtual yang berisi referensi ke objek yang dimaksud. Meskipun DLL tidak dimuat, Proxy dapat menawarkan perilaku default tertentu kepada klien, setelah DLL dimuat, proksi hanya akan meneruskan semua permintaan ke subjek yang sebenarnya.

Proxy virtual akan bertanggung jawab untuk memeriksa inisialisasi DLL dan berdasarkan ini memutuskan apakah permintaan tersebut harus didelegasikan ke subjek nyata.

Pola Proxy di Wikipedia

Bagaimana Anda menyukai ide ini?

edalorzo
sumber
Anda tidak benar-benar menyelesaikan banyak masalah di sini. untuk setiap metode yang ditambahkan di objek aktual, Anda juga perlu menambahkan metode itu ke proxy. Tidak?
Ini menghindari masalah mengingat untuk memanggil init. fungsi, tetapi sepertinya setiap fungsi di proxy masih perlu memeriksa untuk melihat apakah .dll dimuat.
1
@Riram ada perbedaan besar sekarang, menggunakan proxy Anda telah membatasi pemeliharaan terkait dengan pemeriksaan DLL ke satu kelas: proxy. Klien kelas bahkan tidak perlu tahu tentang pemeriksaan DLL sama sekali. Karena sebagian besar metode akan melakukan pendelegasian, saya tidak melihat banyak masalah karena harus mengimplementasikan antarmuka di kedua subjek nyata di proxy. Dengan kata lain Anda dapat mencegah penciptaan subjek nyata sampai Anda yakin DLL telah dimuat, dan kemudian Anda tidak perlu memeriksa status DLL setiap saat.
@edalorzo: walaupun idenya bagus, masalahnya di sini adalah bahwa kita sudah berbicara tentang proxy, dan OP mengeluh tentang harus memeriksa setiap metode proxy-nya ...
Matthieu M.
4

Tidak ada yang berguna terjadi jika DLL belum dimuat; objek hanya menghasilkan kesalahan. Apakah ini kesalahan fatal? Bagaimana cara mengatasi kesalahan?

Apakah metodologi pengujian Anda memastikan bahwa kesalahan ini tidak pernah terjadi pada produk jadi?

Kedengarannya seperti pekerjaan untuk pengujian, bukan untuk desain arsitektur. Jangan hanya mengembalikan kesalahan, assertbahwa itu tidak pernah terjadi.

Perbaiki setiap klien dari kelas yang saat ini menangkap dan mengabaikan kesalahan untuk tidak mencoba dan menyebabkannya di tempat pertama.

Pola multithreaded mungkin untuk menetapkan variabel kondisi bersama setelah memuat DLL, dan meminta konstruktor objek menunggu (dan memblokir utas lainnya) hingga DLL dimuat.

Potatoswatter
sumber
Saya pikir Anda benar, tidak ada yang salah dengan melempar pengecualian pada pembuatan objek yang dimaksud jika DLL belum diinisialisasi dengan benar. Kode klien kemudian hanya perlu berurusan dengan pengecualian ini dan pengujian harus memastikan bahwa pengecualian ditangani dengan tepat.
2

Hal pertama: hindari objek global sebagai hama, kecuali kondisinya tidak pernah berubah (konfigurasi).

Sekarang, jika Anda terjebak dengan itu, untuk alasan apa pun, ada beberapa desain yang mungkin bisa membantu Anda.

Saya datang dengan dua ide:

  1. Gunakan Facade untuk memuat DLL. Objek hanya dapat diakses melalui Fasad, Fasad memuat DLL saat membuat dan membuat Instansiate objek pada saat yang sama.

  2. Gunakan Proxy, tapi yang pintar;)

Izinkan saya menguraikan poin kedua, karena saya khawatir jawaban @edalorzo mungkin menakutkan Anda:

// Private
static Object& GetObjectImpl() { static Object O; return O; }

// Public
static Object& GetObject() {
  Object& o = GetObjectImpl();
  assert(o.isInitialized() && "Object not initialized yet!");
  return o;
}

Sekarang Anda hanya memiliki satu cek.

Ini juga dapat dilakukan melalui beberapa jenis penunjuk pintar:

Pointer<Object> o;

Di sini Anda hanya menyediakan ruang untuk penunjuk, awalnya nol, dan hanya ketika DLL dimuat Anda benar-benar akan mengalokasikan objek. Semua akses sebelumnya harus meningkatkan pengecualian (NullException: p?) Atau menghentikan program (bersih).

Matthieu M.
sumber
1

Ini pertanyaan yang sulit. Saya merasa bahwa arsitektur dapat membantu masalah ini.

Dari buktinya, sepertinya .dll tidak dimuat saat program dimuat. Hampir terdengar seperti plugin.

Satu hal yang terlintas dalam pikiran adalah bahwa Anda harus menginisialisasi .dll. Pemrogram harus berasumsi bahwa objek tidak akan kembali dengan andal, lagipula. Anda mungkin dapat mengambil keuntungan dari ini ( bool isObjectLoaded() { return isInitialized; }), tetapi Anda pasti akan mendapatkan lebih banyak laporan bug dari cek Anda.

Saya sedang memikirkan seorang singleton.

Jika Anda memanggil singleton, itu harus mengembalikan objek yang benar jika dapat mengambil satu. Jika tidak dapat mengembalikan objek yang benar, maka Anda harus mendapatkan beberapa nilai kesalahan / nullptr / objek dasar kosong. Ini tidak akan berhasil jika benda itu bisa mati pada Anda.

Selain itu, jika Anda membutuhkan beberapa instance objek, Anda dapat menggunakan sesuatu seperti Factory.

Joe Plante
sumber