Berapa banyak antarmuka yang terlalu banyak pada suatu kelas? [Tutup]

28

Saya mungkin akan menganggapnya sebagai bau kode atau bahkan anti-pola untuk memiliki kelas yang mengimplementasikan 23 antarmuka. Jika memang anti-pola, apa yang akan Anda sebut itu? Atau apakah itu hanya tidak mengikuti prinsip tanggung jawab tunggal?

Jonas Elfström
sumber
3
Yah, itu dipertanyakan juga. Jika kelas memiliki 23 metode yang semuanya melayani satu tanggung jawab tunggal (tidak semua kelas membutuhkan begitu banyak metode, tetapi bukan tidak mungkin - terutama jika sebagian besar pembungkus kenyamanan tiga baris di sekitar metode lain), Anda hanya memiliki antarmuka yang terlalu halus; )
Kelas yang dimaksud adalah semacam entitas dan antarmuka sebagian besar ke properti. Ada 113 dari mereka dan hanya empat metode.
Jonas Elfström
6
Saya pikir antarmuka pada dasarnya digunakan untuk mengetik bebek dalam bahasa yang dikompilasi secara statis. Apa masalahnya? :)
ashes999
2
hanya sebuah pertanyaan: apakah semua 113 properti terisi untuk setiap instance entitas ini? Atau apakah itu semacam "entitas bersama" yang digunakan dalam konteks yang berbeda dengan hanya beberapa properti yang diisi?
David
1
Mari kita kembali ke pemahaman konseptual tentang apa yang merupakan "kelas". Kelas adalah satu hal dengan tanggung jawab dan peran yang jelas. Bisakah Anda mendefinisikan objek 23-antarmuka Anda dengan cara ini? Bisakah Anda memposting satu kalimat (non-Joycean) yang cukup meringkas kelas Anda? Jika demikian, maka 23 antarmuka baik-baik saja. Jika tidak, maka itu terlalu besar, terlalu rumit.
Stephen Gross

Jawaban:

36

Keluarga Kerajaan: Mereka tidak melakukan sesuatu yang sangat gila tetapi mereka memiliki satu miliar gelar dan entah bagaimana terkait dengan kebanyakan bangsawan lainnya.

Insinyur Dunia
sumber
:-)))))))))))))
Emilio Garavaglia
Saya akan menekankansomehow
Wolf
23

Saya serahkan bahwa pola anti ini diberi nama Jack of All Trades, atau mungkin Too Many Hats.

Mike Partridge
sumber
2
Bagaimana dengan The Swiss Army Knife?
FrustratedWithFormsDesigner
Tampaknya istilah ini sudah digunakan untuk antarmuka dengan terlalu banyak metode :-) Meskipun itu masuk akal di sini juga.
Jalayn
1
@FrustratedWithFormsDesigner Swiss Army Knife tidak akan pernah memiliki selera buruk memiliki antarmuka bernama IValue yang berisi 30 properti yang 20 didahului oleh kata kunci pengubah baru.
Jonas Elfström
3
+1 untuk Terlalu Banyak topi ... untuk menyembunyikan dewa multi-kepala dengan benar
Newtopian
1
Pisau tentara swiss adalah model penggunaan kembali. yaitu satu "pisau" dapat melakukan metode mungkin jadi itu mungkin analogi yang buruk!
James Anderson
17

Jika saya harus memberi nama, saya pikir saya akan menyebutnya Hydra :

Ular naga

Dalam mitologi Yunani, Lernaean Hydra (bahasa Yunani: Λερναία Ὕδρα) adalah binatang air chthonic seperti ular tanpa nama kuno, dengan ciri-ciri reptilian, (seperti namanya perusak) yang memiliki banyak kepala - penyair menyebutkan lebih banyak kepala daripada pelukis vas bisa cat, dan untuk setiap kepala terputus itu tumbuh dua lagi - dan napas beracun begitu mematikan bahkan jejaknya mematikan.

Yang paling relevan adalah kenyataan bahwa ia tidak hanya memiliki banyak kepala, tetapi terus tumbuh semakin banyak dan tidak mungkin untuk dibunuh karena itu. Itulah pengalaman saya dengan desain semacam ini; pengembang hanya terus memasukkan lebih banyak antarmuka ke dalamnya sampai terlalu banyak untuk ditampung di layar, dan pada saat itu sudah menjadi sangat tertanam dalam desain program dan asumsi bahwa membaginya adalah prospek tanpa harapan (jika Anda mencoba, Anda sebenarnya seringkali berakhir membutuhkan lebih banyak antarmuka untuk menjembatani kesenjangan).

Satu tanda awal dari malapetaka yang akan datang karena "Hydra" adalah seringnya pengecoran dari satu antarmuka ke antarmuka lainnya, tanpa banyak pemeriksaan kewarasan, dan seringkali ke target yang tidak masuk akal, seperti pada:

public void CreateWidget(IPartLocator locator, int widgetTypeId)
{
    var partsNeeded = locator.GetPartsForWidget(widgetTypeId);
    return ((IAssembler)locator).BuildWidget(partsNeeded);
}

Sudah jelas ketika diambil di luar konteks bahwa ada sesuatu yang mencurigakan tentang kode ini, tetapi kemungkinan hal ini terjadi seiring dengan semakin banyak "kepala" suatu objek tumbuh, karena pengembang secara intuitif tahu bahwa mereka selalu berurusan dengan makhluk yang sama.

Good luck pernah melakukan perawatan apapun pada objek yang mengimplementasikan interface 23. Kemungkinan Anda tidak menyebabkan kerusakan pada prosesnya sangat kecil.

Aaronaught
sumber
16

The Allah Obyek datang ke pikiran; satu objek yang tahu bagaimana melakukan SEMUANYA. Ini berasal dari kepatuhan yang rendah terhadap persyaratan "kohesi" dari dua metodologi desain utama; jika Anda memiliki objek dengan 23 antarmuka, Anda memiliki objek yang tahu bagaimana menjadi 23 hal yang berbeda bagi penggunanya, dan 23 hal yang berbeda tersebut kemungkinan besar tidak sejalan dengan satu tugas atau bidang sistem.

Dalam SOLID, meskipun pencipta objek ini jelas telah mencoba mengikuti Prinsip Segregasi Antarmuka, mereka telah melanggar aturan sebelumnya; Prinsip Tanggung Jawab Tunggal. Ada alasannya "SOLID"; S selalu lebih dulu ketika memikirkan desain, dan semua aturan lainnya mengikuti.

Dalam GRASP, pencipta kelas semacam itu telah mengabaikan aturan "Kohesi Tinggi"; GRASP, tidak seperti SOLID, mengajarkan bahwa suatu objek tidak HARUS memiliki tanggung jawab tunggal, tetapi paling tidak ia harus memiliki dua atau tiga tanggung jawab yang sangat erat terkait.

KeithS
sumber
Saya tidak yakin bahwa ini adalah anti-pola Objek Allah, karena Tuhan tidak dibatasi oleh antarmuka apa pun. Terkendala oleh begitu banyak antarmuka bisa mengurangi kemahakuasaan Tuhan. ;) Mungkin ini Obyek Chimera?
FrustratedWithFormsDesigner
Tuhan memiliki banyak wajah, dan dapat menjadi banyak hal bagi banyak orang. Jika fungsi dari antarmuka gabungan membuat objek "serba tahu" itu tidak benar-benar membatasi Tuhan, bukan?
KeithS
1
Kecuali apa yang dibuat antarmuka memodifikasinya. Maka Tuhan mungkin harus diterapkan kembali agar sesuai dengan perubahan antarmuka.
FrustratedWithFormsDesigner
3
Sungguh menyakitkan bahwa Anda berpikir bahwa sayalah yang menciptakan kelas.
Jonas Elfström
Penggunaan "Anda" lebih jamak Anda, mengacu pada tim dev Anda. SESEORANG di tim itu, dulu atau sekarang, membuat kelas ini. Saya akan mengedit.
KeithS
8

23 adalah Hanya angka! Dalam skenario yang paling mungkin, cukup tinggi untuk mengkhawatirkan. Namun, jika kita bertanya, berapa jumlah metode / antarmuka tertinggi sebelum bisa mendapatkan tag untuk disebut sebagai "anti-pola"? Apakah 5 atau 10 atau 25? Anda menyadari bahwa angka benar-benar bukan jawaban karena jika 10 baik, 11 juga bisa menjadi - dan kemudian bilangan bulat setelah itu.

Pertanyaan sebenarnya adalah tentang kompleksitas. Dan kita harus menunjukkan bahwa kode panjang, jumlah metode atau ukuran besar kelas dengan ukuran apa pun sebenarnya BUKAN definisi kompleksitas. Ya, kode yang lebih besar dan lebih besar (lebih banyak metode) membuatnya sulit dibaca dan dipahami oleh pemula yang baru. Ini juga menangani fungsionalitas yang berpotensi beragam, sejumlah besar pengecualian, dan algoritma yang cukup berkembang untuk berbagai skenario. Ini tidak berarti kompleks - hanya sulit untuk dicerna.

Di sisi lain, kode ukuran yang relatif kecil yang bisa dibaca seseorang dalam beberapa jam masuk dan keluar masih bisa rumit. Inilah saatnya saya berpikir kodenya kompleks (tidak perlu).

Setiap bagian dari kebijaksanaan desain berorientasi objek dapat diletakkan di sini untuk mendefinisikan "kompleks" tetapi saya akan membatasi di sini untuk menunjukkan kapan "begitu banyak metode" merupakan indikasi kompleksitas.

  1. Saling Mengetahui (alias kopling) Banyak kali ketika sesuatu ditulis sebagai kelas, kita semua berpikir itu adalah kode berorientasi objek yang "bagus". Tetapi asumsi tentang kelas lain pada dasarnya memecah enkapsulasi yang sangat dibutuhkan. Ketika Anda memiliki metode yang "membocorkan" detail mendalam tentang keadaan internal algoritma - dan aplikasi dibangun dengan asumsi utama tentang keadaan internal kelas melayani.

  2. Terlalu banyak pengulangan (pembobolan) Ketika metode yang memiliki nama serupa tetapi melakukan pekerjaan yang bertentangan - atau bertentangan dengan nama dengan fungsi yang sama. Banyak kode yang berevolusi untuk mendukung antarmuka yang sedikit berbeda untuk aplikasi yang berbeda.

  3. Terlalu banyak peran Ketika kelas terus menambahkan fungsi samping dan terus berkembang lebih seperti orang menyukainya, hanya untuk mengetahui bahwa kelas itu sekarang menjadi dua kelas. Yang mengejutkan semua ini dimulai dengan yang aslipersyaratan dan tidak ada kelas lain untuk melakukan ini. Pertimbangkan ini, ada Transaksi kelas, yang memberi tahu detail transaksi. Terlihat bagus sejauh ini, sekarang seseorang memerlukan konversi format pada "waktu transaksi" (antara UTC dan sejenisnya), kemudian, orang menambahkan aturan untuk memeriksa apakah ada hal-hal tertentu pada tanggal tertentu untuk memvalidasi transaksi yang tidak valid. - Saya tidak akan menulis keseluruhan cerita tetapi akhirnya, kelas transaksi membangun seluruh kalender dengan di dalamnya dan kemudian orang-orang mulai menggunakan bagian "hanya kalender"! Ini sangat kompleks (untuk membayangkan) mengapa saya akan instantiate "kelas transaksi" untuk memiliki fungsionalitas bahwa "kalender" akan memberi saya!

  4. (Dalam) konsistensi API Ketika saya melakukan book_a_ticket () - Saya memesan tiket! Itu sangat sederhana terlepas dari berapa banyak pemeriksaan dan proses untuk mewujudkannya. Sekarang menjadi rumit ketika aliran waktu mulai mempengaruhi ini. Biasanya seseorang akan memungkinkan "mencari" dan kemungkinan status yang tersedia / tidak tersedia, kemudian untuk mengurangi back-n-sebagainya Anda mulai menyimpan beberapa pointer konteks di dalam tiket dan kemudian merujuknya untuk memesan tiket. Pencarian bukan satu-satunya fungsi - hal menjadi lebih buruk setelah banyak "fungsi samping" tersebut. Dalam proses arti book_a_ticket () menyiratkan book_that_ticket ()! dan itu bisa sangat rumit.

Mungkin ada banyak situasi seperti itu yang akan Anda lihat dalam kode yang sangat berkembang dan saya yakin bahwa banyak orang dapat menambahkan skenario, di mana "begitu banyak metode" tidak masuk akal atau tidak melakukan apa yang Anda pikirkan. Ini adalah anti-pola.

Pengalaman pribadi saya adalah bahwa ketika proyek yang dimulai dari bawah ke atas secara wajar , banyak hal yang seharusnya memiliki kelas asli sendiri - tetap terkubur atau lebih buruk masih tetap terbagi antara kelas yang berbeda dan peningkatan kopling. Paling sering apa yang seharusnya layak 10 kelas, tetapi hanya memiliki 4, kemungkinan banyak dari mereka memiliki multi-tujuan yang membingungkan dan sejumlah besar metode. Sebut saja TUHAN dan NAGA, inilah yang BURUK.

TAPI Anda menemukan kelas SANGAT BESAR yang konsisten dengan rapi, mereka memiliki 30 metode - dan masih sangat BERSIH. Mereka bisa baik.

Dipan Mehta
sumber
Kelas dalam pertanyaan memiliki 23 antarmuka dan ini berisi, semuanya, 113 properti umum dan empat metode. Hanya beberapa dari mereka yang bisa dibaca. C # memiliki sifat auto-dilaksanakan, itu sebabnya aku berbeda antara metode dan properti msdn.microsoft.com/en-us/library/bb384054.aspx
Jonas Elfström
7

Kelas harus memiliki jumlah antarmuka yang tepat; tidak lebih, tidak kurang.

Mengatakan "terlalu banyak" tidak akan mungkin tanpa melihat apakah semua antarmuka tersebut memiliki tujuan yang berguna di kelas itu. Mendeklarasikan bahwa objek mengimplementasikan antarmuka berarti Anda harus mengimplementasikan metode-metodenya jika Anda mengharapkan kelas untuk dikompilasi. (Saya kira kelas yang Anda lihat tidak.) Jika semua yang ada di antarmuka diimplementasikan dan implementasi tersebut melakukan sesuatu yang relatif terhadap jeroan kelas, akan sulit untuk mengatakan bahwa implementasi tidak boleh ada di sana. Satu-satunya kasus yang saya bisa pikirkan di mana antarmuka memenuhi kriteria itu tidak akan termasuk ada eksternal: ketika tidak ada yang menggunakannya.

Beberapa bahasa memungkinkan antarmuka untuk "subkelas" menggunakan mekanisme seperti extendskata kunci Java , dan siapa pun yang menulisnya mungkin tidak tahu itu. Mungkin juga bahwa ke-23 itu cukup jauh sehingga menggabungkan mereka tidak masuk akal.

Blrfl
sumber
Saya pikir pertanyaan ini cukup agnostik bahasa. Kode aktual dalam C #.
Jonas Elfström
Saya belum melakukan C # apa pun, tetapi tampaknya mendukung bentuk warisan antarmuka yang serupa.
Blrfl
Ya, sebuah antarmuka dapat "mewarisi" antarmuka lain dan sebagainya.
Jonas Elfström
Saya menemukan menarik bahwa banyak diskusi fokus pada apa yang kelas harus melakukan, daripada apa contoh harus melakukan. Robot dengan beragam sensor pencitraan dan audio yang terpasang pada sasis umum harus dimodelkan sebagai entitas yang memiliki lokasi dan orientasi, dan yang dapat melihat, dan mendengar, serta mengaitkan pemandangan dan suara. Semua logika nyata di balik fungsi-fungsi itu mungkin ada di kelas lain, tetapi robot itu sendiri harus mendukung metode seperti "lihat apakah ada objek di depan", "dengarkan suara apa pun di area", atau "lihat apakah objek di depan terlihat seperti itu menghasilkan suara yang terdeteksi. "
supercat
Mungkin saja robot tertentu harus membagi fungsinya menjadi subsistem dengan cara tertentu, tetapi sejauh kode praktis yang menggunakan robot tidak harus tahu atau peduli tentang bagaimana fungsi dalam robot tertentu dibagi lagi. Jika "mata" dan "telinga" terpapar ke dunia luar sebagai objek yang terpisah, tetapi sensor yang sesuai berada di lengan ekstensi bersama, kode luar mungkin meminta "telinga" untuk mendengarkan suara di permukaan tanah pada saat yang sama dengan ia meminta "mata" untuk melihat di atas rintangan.
supercat
1

Kedengarannya seperti mengira mereka memiliki pasangan "pengambil" / "penyetel" untuk setiap properti, seperti biasa untuk "kacang" khas dan mempromosikan semua metode ini ke antarmuka. Jadi bagaimana kalau menyebutnya " kacang ". Atau "perut kembung" yang lebih Rabelaisian setelah pengaruh yang dikenal dari terlalu banyak kacang.

James Anderson
sumber
Ada di C # dan memiliki Properti yang Diimplementasikan Otomatis. 23 antarmuka ini, semuanya, berisi 113 properti seperti itu.
Jonas Elfström
1

Jumlah antarmuka sering bertambah ketika objek generik digunakan di lingkungan yang berbeda. Dalam C # varian IComparable, IEqualityComparer dan IComparer memungkinkan pengurutan dalam pengaturan yang berbeda, sehingga Anda mungkin akhirnya mengimplementasikan semuanya, beberapa di antaranya mungkin lebih dari sekali karena Anda dapat mengimplementasikan versi generik yang diketik dengan kuat serta versi non-generik , selain itu Anda dapat menerapkan lebih dari satu obat generik.

Mari kita ambil contoh skenario, katakanlah sebuah toko web di mana Anda dapat membeli kredit yang dengannya Anda dapat membeli sesuatu yang lain (stok situs foto sering menggunakan skema ini). Anda mungkin memiliki kelas "Valuta" dan kelas "Kredit" yang mewarisi bentuk basis yang sama. Valuta memiliki beberapa kelebihan operator dan rutinitas perbandingan yang memungkinkan Anda melakukan perhitungan tanpa khawatir tentang properti "Mata Uang" (misalnya, menambahkan pound ke dolar). Kredit lebih mudah tetapi memiliki beberapa perilaku berbeda lainnya. Ingin dapat membandingkan ini satu sama lain, Anda bisa akhirnya mengimplementasikan IComparable serta IComparable dan varian lain dari antarmuka perbandingan pada keduanya (meskipun mereka menggunakan implementasi umum apakah itu di kelas dasar atau di tempat lain).

Ketika menerapkan serialisasi, ISerializable, IDeserializationCallback diimplementasikan. Kemudian menerapkan tumpukan undo-redo: IClonable ditambahkan. Fungsionalitas IsDirty: IObservable, INotifyPropertyChanged. Mengizinkan pengguna mengedit nilai menggunakan string: IConvertable ... Daftar ini bisa berlanjut dan terus ...

Dalam bahasa modern kita melihat tren berbeda yang membantu memisahkan aspek-aspek ini dan menempatkannya di kelas mereka sendiri, di luar kelas inti. Kelas atau aspek luar kemudian dikaitkan dengan kelas target dengan menggunakan anotasi (atribut). Seringkali dimungkinkan untuk membuat kelas aspek luar lebih atau kurang generik.

Penggunaan atribut (anotasi) tunduk pada refleksi. Satu kelemahan adalah kerugian kinerja (awal) kecil. Kelemahan (sering emosional) adalah bahwa prinsip-prinsip seperti enkapsulasi perlu santai.

Selalu ada solusi lain, tetapi untuk setiap solusi bagus ada tradeoff atau tangkapan. Misalnya, menggunakan solusi ORM mungkin menuntut semua properti dinyatakan virtual. Solusi serialisasi mungkin menuntut konstruktor default di kelas Anda. Jika Anda menggunakan injeksi dependensi Anda mungkin akhirnya mengimplementasikan 23 antarmuka pada satu kelas.

Di mata saya, 23 antarmuka tidak harus buruk menurut definisi. Mungkin ada skema dipikirkan dengan baik di belakangnya, atau beberapa prinsip penentuan seperti menghindari penggunaan refleksi atau keyakinan enkapsulasi ekstrim.

Setiap kali berganti pekerjaan, atau harus membangun arsitektur yang sudah ada. Saran saya adalah pertama-tama berkenalan sepenuhnya, jangan mencoba untuk memperbaiki semuanya terlalu cepat. Dengarkan pengembang asli (jika dia masih di sana) dan cobalah untuk mencari tahu pikiran dan ide di balik apa yang Anda lihat. Saat mengajukan pertanyaan, lakukan itu bukan demi memecahnya, tetapi untuk belajar ... Ya, setiap orang memiliki palu emas sendiri, tetapi semakin banyak palu yang dapat Anda kumpulkan semakin mudah Anda bergaul dengan rekan-rekan sesama.

Louis Somers
sumber
0

"Terlalu banyak" adalah subyektif: gaya pemrograman? kinerja? kesesuaian dengan standar? preseden? sekadar rasa nyaman / percaya diri?

Selama kode Anda berperilaku benar dan tidak menghadirkan masalah pemeliharaan, 23 bahkan bisa menjadi norma baru. Suatu hari nanti saya bisa berkata, "Anda dapat melakukan pekerjaan yang sangat baik dengan 23 antarmuka, lihat: Jonas Elfström".

Keris
sumber
0

Saya akan mengatakan bahwa batasnya harus lebih kecil dari 23 - lebih seperti 5 atau 7,
namun, ini tidak termasuk sejumlah antarmuka yang diwariskan oleh antarmuka tersebut atau sejumlah antarmuka yang diterapkan oleh kelas dasar.

(Jadi sama sekali, N + sejumlah antarmuka yang diwariskan, di mana N <= 7.)

Jika kelas Anda mengimplementasikan terlalu banyak antarmuka, itu mungkin kelas dewa .

Danny Varod
sumber