Dari Pengembangan Perangkat Lunak, Prinsip, Pola, dan Praktek Agile: Pearson New International Edition :
Terkadang, metode yang digunakan oleh berbagai kelompok klien akan tumpang tindih. Jika tumpang tindih kecil, maka antarmuka untuk grup harus tetap terpisah. Fungsi umum harus dideklarasikan di semua antarmuka yang tumpang tindih. Kelas server akan mewarisi fungsi-fungsi umum dari masing-masing antarmuka tersebut, tetapi akan mengimplementasikannya hanya sekali.
Paman Bob, berbicara tentang kasus ketika ada tumpang tindih kecil.
Apa yang harus kita lakukan jika ada tumpang tindih yang signifikan?
Katakan kita punya
Class UiInterface1;
Class UiInterface2;
Class UiInterface3;
Class UiIterface : public UiInterface1, public UiInterface2, public UiInterface3{};
Apa yang harus kita lakukan jika ada tumpang tindih yang signifikan antara UiInterface1
dan UiInterface2
?
Jawaban:
Pengecoran
Ini hampir pasti akan menjadi garis singgung lengkap dengan pendekatan buku yang dikutip, tetapi satu cara untuk menyesuaikan diri dengan ISP adalah dengan merangkul pola pikir casting di satu area pusat basis kode Anda menggunakan
QueryInterface
pendekatan gaya-COM.Banyak godaan untuk mendesain antarmuka yang tumpang tindih dalam konteks antarmuka murni seringkali berasal dari keinginan untuk membuat antarmuka "mandiri" lebih dari melakukan satu tanggung jawab yang tepat, seperti penembak jitu.
Misalnya, mungkin tampak aneh untuk mendesain fungsi klien seperti ini:
... juga sangat jelek / berbahaya, mengingat bahwa kita membocorkan tanggung jawab untuk melakukan pengecoran rawan kesalahan ke kode klien menggunakan antarmuka ini dan / atau melewatkan objek yang sama sebagai argumen beberapa kali ke beberapa parameter yang sama fungsi. Jadi kita akhirnya sering ingin merancang antarmuka yang lebih terdilusi yang mengkonsolidasikan keprihatinan
IParenting
danIPosition
di satu tempat, sepertiIGuiElement
atau sesuatu seperti itu yang kemudian menjadi rentan terhadap tumpang tindih dengan masalah antarmuka ortogonal yang juga akan tergoda untuk memiliki lebih banyak fungsi anggota untuk alasan "swasembada" yang sama.Mencampur Tanggung Jawab vs. Casting
Ketika merancang antarmuka dengan tanggung jawab ultra-singular yang benar-benar disuling, godaan sering kali adalah menerima beberapa antarmuka yang downcasting atau menggabungkan untuk memenuhi beberapa tanggung jawab (dan karenanya menginjak baik ISP maupun SRP).
Dengan menggunakan pendekatan gaya-COM (hanya
QueryInterface
bagian), kami bermain dengan pendekatan downcasting tetapi mengkonsolidasikan casting ke satu tempat sentral dalam basis kode, dan dapat melakukan sesuatu yang lebih seperti ini:... tentu saja mudah-mudahan dengan pembungkus tipe-aman dan semua yang Anda dapat membangun secara terpusat untuk mendapatkan sesuatu yang lebih aman daripada pointer mentah.
Dengan ini, godaan untuk mendesain antarmuka yang tumpang tindih sering dikurangi seminimal mungkin. Hal ini memungkinkan Anda untuk mendesain antarmuka dengan tanggung jawab yang sangat tunggal (kadang-kadang hanya satu fungsi anggota di dalamnya) yang Anda dapat mencampur dan mencocokkan semua yang Anda suka tanpa khawatir tentang ISP, dan mendapatkan fleksibilitas mengetik pseudo-bebek saat runtime di C ++ (meskipun tentu saja dengan trade-off dari penalti runtime ke objek permintaan untuk melihat apakah mereka mendukung antarmuka tertentu). Bagian runtime dapat menjadi penting dalam, katakanlah, pengaturan dengan kit pengembangan perangkat lunak di mana fungsi tidak akan memiliki informasi waktu kompilasi dari plugin sebelumnya yang mengimplementasikan antarmuka ini.
Templat
Jika templat adalah suatu kemungkinan (kami memiliki info waktu kompilasi yang diperlukan di muka yang tidak hilang pada saat kami mendapatkan suatu objek, yaitu), maka kami dapat melakukannya:
... tentu saja dalam kasus seperti itu,
parent
metode harus mengembalikanEntity
tipe yang sama , dalam hal ini kita mungkin ingin menghindari antarmuka langsung (karena mereka akan sering ingin kehilangan informasi jenis yang mendukung bekerja dengan basis pointer).Sistem Entitas-Komponen
Jika Anda mulai mengejar pendekatan gaya COM lebih jauh dari sudut pandang fleksibilitas atau kinerja, Anda akan sering berakhir dengan sistem komponen entitas yang mirip dengan apa yang diterapkan mesin game di industri. Pada titik itu Anda akan benar-benar tegak lurus terhadap banyak pendekatan berorientasi objek, tetapi ECS mungkin berlaku untuk desain GUI (satu tempat yang saya renungkan menggunakan ECS di luar fokus berorientasi adegan, tetapi menganggapnya terlambat setelah menetapkan pendekatan gaya COM untuk mencoba di sana).
Perhatikan bahwa solusi gaya-COM ini benar-benar ada di luar sana sejauh desain alat GUI berjalan, dan ECS akan lebih, jadi itu bukan sesuatu yang akan didukung oleh banyak sumber daya. Namun itu pasti akan memungkinkan Anda untuk mengurangi godaan untuk merancang antarmuka yang memiliki tanggung jawab yang tumpang tindih ke minimum absolut, sering menjadikannya tidak menjadi perhatian.
Pendekatan Pragmatis
Alternatifnya, tentu saja, sedikit rileks penjaga Anda, atau desain antarmuka di tingkat granular dan kemudian mulai mewarisi mereka untuk membuat antarmuka kasar yang Anda gunakan, seperti
IPositionPlusParenting
yang berasal dari keduanyaIPosition
danIParenting
(semoga dengan nama yang lebih baik dari itu). Dengan antarmuka murni, seharusnya tidak melanggar ISP sebanyak pendekatan monolitik mendalam-hierarki yang biasa diterapkan (Qt, MFC, dll. Di mana dokumentasi sering merasa perlu untuk menyembunyikan anggota yang tidak relevan mengingat tingkat pelanggaran ISP yang berlebihan dengan jenis-jenis itu). desain), sehingga pendekatan pragmatis mungkin hanya menerima beberapa tumpang tindih di sana-sini. Namun pendekatan gaya-COM semacam ini menghindari perlunya membuat antarmuka terkonsolidasi untuk setiap kombinasi yang pernah Anda gunakan. Perhatian "swasembada" sepenuhnya dihilangkan dalam kasus-kasus seperti itu, dan itu akan sering menghilangkan sumber utama godaan untuk merancang antarmuka yang memiliki tanggung jawab yang tumpang tindih yang ingin bertarung dengan SRP dan ISP.sumber
Ini adalah panggilan penilaian yang harus Anda buat, berdasarkan kasus per kasus.
Pertama-tama, ingatlah bahwa prinsip-prinsip SOLID hanyalah ... prinsip. Itu bukan aturan. Itu bukan peluru perak. Itu hanya prinsip. Itu tidak mengambil dari pentingnya mereka, Anda harus selalu cenderung mengikuti mereka. Namun begitu mereka menimbulkan rasa sakit, Anda harus membuangnya sampai Anda membutuhkannya.
Dengan mengingat hal itu, pikirkan mengapa Anda memisahkan antarmuka Anda. Gagasan sebuah antarmuka adalah untuk mengatakan "Jika kode konsumsi ini memerlukan seperangkat metode yang harus diimplementasikan pada kelas yang dikonsumsi, saya perlu menetapkan kontrak pada implementasi: Jika Anda memberi saya objek dengan antarmuka ini, saya dapat bekerja dengan itu. "
Tujuan ISP adalah untuk mengatakan "Jika kontrak yang saya butuhkan hanya sebagian dari antarmuka yang ada, saya tidak boleh memaksakan antarmuka yang ada pada setiap kelas di masa depan yang dapat diteruskan ke metode saya."
Pertimbangkan kode berikut:
Sekarang kita memiliki situasi di mana, jika kita ingin meneruskan objek baru ke ConsumeX, ia harus mengimplementasikan X () dan Y () agar sesuai dengan kontrak.
Jadi haruskah kita mengubah kodenya, sekarang, agar terlihat seperti contoh berikut?
ISP menyarankan kita harus, jadi kita harus condong ke arah keputusan itu. Tetapi, tanpa konteks, sulit untuk memastikan. Apakah mungkin kami akan memperpanjang A dan B? Apakah mungkin mereka akan memperluas secara mandiri? Apakah mungkin B akan pernah menerapkan metode yang tidak diperlukan oleh A? (Jika tidak, kita dapat membuat A berasal dari B.)
Ini adalah panggilan penghakiman yang harus Anda lakukan. Dan, jika Anda benar-benar tidak memiliki cukup informasi untuk melakukan panggilan itu, Anda mungkin harus mengambil opsi paling sederhana, yang mungkin merupakan kode pertama.
Mengapa? Karena mudah untuk berubah pikiran nanti. Saat Anda membutuhkan kelas baru itu, cukup buat antarmuka baru dan terapkan keduanya di kelas lama Anda.
sumber