Bagaimana cara menghindari jumlah antarmuka yang gila di UI dengan injeksi ketergantungan?

8

Masalah
Saya baru-baru ini membaca banyak tentang Singletons yang buruk dan bagaimana injeksi ketergantungan (yang saya pahami sebagai "menggunakan antarmuka") lebih baik. Ketika saya menerapkan bagian ini dengan callbacks / interfaces / DI dan mengikuti prinsip pemisahan antarmuka, saya berakhir dengan cukup berantakan.

Ketergantungan dari induk UI di mana pada dasarnya anak-anak dari semua anak-anaknya digabungkan, sehingga semakin tinggi hirarki elemen UI, semakin konstruksinya semakin besar.

Semua jalan di atas hirarki UI adalah kelas Aplikasi, memegang info tentang pilihan saat ini dan referensi ke model 3d yang perlu mencerminkan perubahan. Kelas aplikasi mengimplementasikan 8 antarmuka, dan ini hanya sekitar seperlima dari produk (/ antarmuka) yang akan datang!

Saat ini saya bekerja dengan singleton yang memegang seleksi saat ini dan elemen UI memiliki fungsi untuk memperbarui diri. Fungsi ini menetes ke bawah pohon UI dan elemen UI kemudian mengakses singleton pilihan saat ini sesuai kebutuhan. Bagi saya, kode ini tampak lebih bersih.

Pertanyaan
Apakah tunggal mungkin yang sesuai untuk proyek ini?
Jika tidak, apakah ada cacat mendasar dalam pemikiran dan / atau implementasi DI saya yang membuatnya sangat rumit?

Info tambahan tentang proyek
Jenis: Keranjang belanja untuk apartemen, dengan lonceng dan peluit
Ukuran: 2 man-bulan untuk kode dan
Pemeliharaan UI : Tidak ada pembaruan berjalan, tapi mungkin "versi 2.0" nanti
Lingkungan: Menggunakan C # di Unity, yang menggunakan Entity Sistem komponen

Dalam hampir semua kasus, interaksi pengguna memicu beberapa tindakan. Misalnya, ketika pengguna memilih item

  • bagian UI yang menunjukkan item itu dan uraiannya perlu diperbarui. Untuk ini, ia juga perlu mendapatkan beberapa info dari model 3d untuk menghitung harganya.
  • lanjut ke UI, harga total keseluruhan perlu diperbarui
  • fungsi yang sesuai di kelas pada model 3d perlu dipanggil untuk menampilkan perubahan di sana
R. Schmitz
sumber
DI bukan hanya tentang menggunakan antarmuka, ini adalah kemampuan untuk bertukar konkret yang sangat berguna dalam bidang pengujian unit ...
Robbie Dee
1
Juga, saya belum melihat masalah di mana singleton adalah solusi yang disukai. Contoh kanonik yang selalu dinyatakan oleh orang adalah penulis log, tetapi bahkan di sini Anda mungkin ingin menulis ke sejumlah log yang berbeda (kesalahan, debug, dll.).
Robbie Dee
@RobbieDee Ya, DI adalah tentang lebih banyak, tapi saya tidak bisa melihat situasi di mana menggunakan antarmuka tidak DI. Dan jika singleton bukan solusi yang disukai - yang juga saya asumsikan - lalu mengapa solusi yang disukai sangat berantakan? Itu adalah pertanyaan utama saya, tetapi saya ingin tetap membuka, karena kadang-kadang aturan umum tidak berlaku.
R. Schmitz
Pengaturan antarmuka-konkret juga merupakan fitur kerangka kerja mengejek. Mereka juga sudah menggunakan bahasa OO selama beberapa dekade ...
Robbie Dee
Saya tidak mengerti maksud Anda.
R. Schmitz

Jawaban:

4

Saya pikir pertanyaannya adalah gejala, bukan solusi.

Saya baru-baru ini membaca banyak tentang Singletons yang buruk dan bagaimana injeksi ketergantungan (yang saya pahami sebagai "menggunakan antarmuka") lebih baik. Ketika saya menerapkan bagian ini dengan callbacks / interfaces / DI dan mengikuti prinsip pemisahan antarmuka, saya berakhir dengan cukup berantakan.

Solusi mencari masalah; itu dan kesalahpahaman itu mungkin merusak desain Anda. Sudahkah Anda membaca pertanyaan SO tentang DI vs Singleton, konsep yang berbeda atau tidak? Saya membaca bahwa hanya dengan membungkus singleton sehingga klien tidak harus berurusan dengan singleton. It.is.just.good.old.encapsulation. Saya pikir itu tepat.


semakin tinggi hierarki elemen UI, semakin konstruksinya semakin besar.

Bangun bit yang lebih kecil terlebih dahulu kemudian masukkan ke dalam konstruktor dari benda yang mereka miliki dan berikan benda yang lebih besar ke dalam konstruktor hal yang lebih besar berikutnya ...

Jika Anda memiliki masalah konstruksi yang kompleks, gunakan pola pabrik atau pembangun. Intinya ada konstruksi kompleks yang ditarik ke kelasnya sendiri untuk menjaga kelas lain tetap rapi, bersih, mudah dipahami, dll.


Kelas aplikasi mengimplementasikan 8 antarmuka, dan ini hanya sekitar seperlima dari produk (/ antarmuka) yang akan datang!

Ini terdengar seperti tidak adanya perpanjangan kemampuan. Desain inti tidak ada dan semuanya dijejali dari atas. Seharusnya ada lebih banyak konstruksi, komposisi, dan pewarisan dari bawah ke atas yang terjadi.

Saya ingin tahu apakah desain Anda "sangat berat." Kedengarannya seperti kita sedang berusaha membuat satu kelas menjadi segalanya atau apapun itu. Dan fakta bahwa itu adalah kelas UI, bukan kelas domain bisnis, yang benar-benar membuat saya bertanya-tanya tentang pemisahan masalah.

Tinjau kembali desain Anda dari awal dan pastikan ada abstraksi produk yang solid dan mendasar yang dapat dibangun untuk membuat produksi kategori yang lebih kompleks atau berbeda. Maka Anda lebih baik memiliki koleksi khusus dari hal-hal ini sehingga Anda memiliki tempat untuk meletakkan fungsionalitas "tingkat koleksi" - seperti "model ke-3" yang Anda sebutkan.


... model 3d yang perlu mencerminkan perubahan.

Banyak dari ini mungkin cocok di kelas koleksi kustom. Mungkin juga struktur kelas yang independen karena kedalaman dan kompleksitas. Kedua hal ini tidak saling eksklusif.

Baca tentang pola pengunjung. Ini adalah ide untuk memiliki seluruh chuck fungsionalitas kabel secara abstrak ke berbagai jenis.


Desain dan DI

90% dari semua injeksi dependensi yang akan Anda lakukan adalah melewati konstruktor parameter. Demikian kata quy yang menulis buku itu . Rancang kelas Anda dengan baik dan hindari mencemari proses berpikir itu dengan gagasan yang samar-samar tentang perlunya menggunakan wadah-benda DI. Jika Anda membutuhkannya, desain Anda akan menyarankannya untuk Anda.


Fokus pada pemodelan domain belanja apartemen.

Hindari pendekatan Jessica Simpson untuk mendesain : "Saya sama sekali tidak tahu apa artinya itu, tetapi saya menginginkannya."

Berikut ini salah:

  • Saya seharusnya menggunakan antarmuka
  • Saya tidak seharusnya menggunakan singleton
  • Saya perlu DI (apa pun itu)
  • Saya seharusnya menggunakan komposisi, bukan warisan
  • Saya seharusnya menghindari warisan
  • Saya perlu menggunakan pola
radarbob
sumber
Saya mencoba menyingkirkan semua lajang yang saya gunakan dan beberapa hal yang Anda katakan terjadi kurang lebih secara otomatis. Sisanya sangat masuk akal, dan saya akan mengambil saran Anda dan membaca tentang pola pengunjung dll. Semua dalam semua jawaban yang ditulis dengan baik, terima kasih!
R. Schmitz
Hanya satu titik, dan aku tidak berusaha untuk menjadi bantuan vampir di sini, tapi itu semacam bagian dari pertanyaan awal: Konsensus umum (dan itu didasarkan pada alasan yang sah) tampaknya menjadi bahwa Anda memang tidak seharusnya gunakan singleton. Anda menulis "'Saya tidak seharusnya menggunakan singleton' itu salah" - dalam situasi apa yang tepat untuk menggunakannya?
R. Schmitz
Yang saya katakan adalah, "itu tergantung." Terlalu sering saya melihat maksim diambil secara harfiah.
radarbob
3

"Class heirarchy" adalah sedikit bendera merah. Hipotetis: halaman web dengan 5 widget. Halaman ini bukan merupakan leluhur dari salah satu widget. Ini mungkin memiliki referensi ke widget tersebut. Tapi itu bukan leluhur. Alih-alih hirarki kelas, pertimbangkan untuk menggunakan komposisi. Masing-masing dari 5 widget dapat dibangun sendiri, tanpa merujuk ke widget lain atau halaman atas. Halaman atas kemudian dibangun dengan informasi yang cukup untuk membangun halaman dasar dan tata letak objek widget (Koleksi) yang diteruskan ke sana. Halaman ini bertanggung jawab untuk tata letak, dll, tetapi tidak untuk konstruksi dan logika widget.

Setelah Anda menggunakan komposisi, DI adalah teman terbaik Anda. DI memungkinkan Anda menukar setiap widget untuk versi atau tipe widget apa pun yang Anda tetapkan dalam DI. Konstruksi widget ditangkap dalam DI dan terpisah dari halaman atas. Mungkin bahkan komposisi Koleksi dapat didefinisikan dalam DI Anda. Halaman atas melakukan tata letak berdasarkan widget yang diteruskan ke sana, sebagaimana mestinya. Tidak diperlukan perubahan pada konstruktor halaman atas. Halaman atas hanya membutuhkan logika untuk melakukan tata letak widget dan meneruskan info ke / dari widget berdasarkan antarmuka yang ditentukan.

Alih-alih melewati pendengar ke atas dan ke bawah rantai komposisi, menyuntikkan koleksi pendengar ke widget yang membutuhkannya. Suntikkan koleksi ke penerbit sehingga mereka dapat mempublikasikan ke koleksi. Suntikkan koleksi di pendengar sehingga mereka dapat menambahkan diri ke koleksi. Koleksi memotong semua objek dalam rantai komposisi.

scorpdaddy
sumber
Maaf, "hierarki kelas" salah diucapkan di sini; sebenarnya bukan hierarki kelas, melainkan hierarki UI. 'Widget' bukan subkelas dari kelas aplikasi, tetapi 'halaman' memiliki referensi untuk mempublikasikan pembaruan UI. Itu sangat dapat diuji dengan struktur ini, tetapi ada juga banyak overhead terutama di konstruktor, hanya meneruskan banyak pendengar untuk anak-anak mereka (UI).
R. Schmitz
@ R.Schmitz: Apakah masalah overhead? Apakah UI lamban, dan apakah desain yang Anda deskripsikan salah?
Robert Harvey
@ R.Schmitz Bisakah Anda menguraikan "menyampaikan banyak pendengar"? Mungkin pengalaman saya dengan DI di C # rendah, tetapi ada sesuatu yang memberitahu saya bahwa tidak perlu (setidaknya di konstruktor) dengan desain yang tepat.
Katana314
@RobertHarvey Tidak ada kehilangan kinerja sama sekali, ini hanya tentang keterbacaan.
R. Schmitz
@ Katana314 Misalnya, ketika suatu item ditambahkan, model 3d perlu diperbarui dan itu tidak termasuk dalam kategori produk mana pun, sehingga direferensikan dalam kelas aplikasi, yang mendengarkan item yang ditambahkan / dihapus / diubah. Pada akhirnya itu akan sama untuk setiap kategori produk. Bagian UI lain juga bereaksi (dan mendengarkan), tetapi pesan tersebut perlu melakukan perjalanan ke atas karena di situlah referensi model 3d dan data aktual (yang kemudian juga diperbarui) adalah.
R. Schmitz