Saya telah tumbuh menggunakan prinsip untuk mendesain dan mengonsumsi antarmuka yang pada dasarnya mengatakan, "minta hanya apa yang Anda butuhkan."
Misalnya, jika saya memiliki banyak jenis yang dapat dihapus, saya akan membuat Deletable
antarmuka:
interface Deletable {
void delete();
}
Maka saya bisa menulis kelas generik:
class Deleter<T extends Deletable> {
void delete(T t) {
t.delete();
}
}
Di tempat lain dalam kode saya akan selalu meminta tanggung jawab sekecil mungkin untuk memenuhi kebutuhan kode klien. Jadi jika saya hanya perlu menghapus File
, saya akan tetap meminta Deletable
, bukan a File
.
Apakah prinsip ini adalah pengetahuan umum dan sudah memiliki nama yang diterima? Apakah ini kontroversial? Apakah ini dibahas dalam buku teks?
object-oriented
interfaces
solid
single-responsibility
glenviewjeff
sumber
sumber
Jawaban:
Saya percaya bahwa ini merujuk pada apa yang Robert Martin sebut sebagai Prinsip Segregasi Antarmuka . Antarmuka dipisahkan menjadi yang kecil dan ringkas sehingga konsumen (klien) hanya perlu tahu tentang metode yang menarik bagi mereka. Anda dapat memeriksa lebih lanjut tentang SOLID .
sumber
Untuk memperluas jawaban Vadim yang sangat baik, saya akan menjawab pertanyaan "apakah ini kontroversial" dengan "tidak, tidak benar-benar".
Secara umum, pemisahan antarmuka adalah hal yang baik, dengan mengurangi jumlah keseluruhan "alasan untuk berubah" dari berbagai objek yang terlibat. Prinsip intinya adalah, ketika sebuah antarmuka dengan beberapa metode harus diubah, katakanlah untuk menambahkan parameter ke salah satu metode antarmuka, maka semua konsumen antarmuka setidaknya harus dikompilasi ulang, bahkan jika mereka tidak menggunakan metode yang diubah.. "Tapi itu hanya kompilasi ulang!", Saya mendengar Anda berkata; itu mungkin benar, tetapi perlu diingat bahwa biasanya, apa pun yang Anda kompilasi ulang harus didorong keluar sebagai bagian dari tambalan perangkat lunak, tidak peduli seberapa penting perubahan ke biner. Aturan-aturan ini awalnya dikonseptualisasikan kembali di awal 90-an, ketika rata-rata workstation desktop kurang kuat daripada ponsel di saku Anda, dial-up baud 14,4k sangat mencolok, dan "disket" 1,44MB "disket" adalah media utama yang dapat dilepas. Bahkan di era 3G / 4G saat ini, pengguna internet nirkabel sering memiliki paket data dengan batasan, jadi ketika merilis upgrade, semakin sedikit binari yang harus diunduh, semakin baik.
Namun, seperti semua ide bagus, pemisahan antarmuka dapat menjadi buruk jika tidak diterapkan dengan benar. Pertama, ada kemungkinan bahwa dengan memisahkan antarmuka sambil menjaga objek yang mengimplementasikan antarmuka tersebut (memenuhi dependensi) relatif tidak berubah, Anda mungkin berakhir dengan "Hydra", kerabat dari "God Object" anti-pola di mana semua-mengetahui, semua-kuat sifat objek disembunyikan dari ketergantungan oleh antarmuka yang sempit. Anda berakhir dengan monster berkepala banyak yang setidaknya sulit untuk mempertahankan seperti Obyek Dewa, ditambah overhead untuk mempertahankan semua antarmuka. Tidak ada banyak antarmuka yang tidak boleh Anda lewati, tetapi setiap antarmuka yang Anda implementasikan pada satu objek harus diawali dengan menjawab pertanyaan, "Apakah antarmuka ini berkontribusi pada objek '
Kedua, antarmuka per metode mungkin tidak diperlukan, terlepas dari apa yang mungkin dikatakan SRP kepada Anda. Anda mungkin berakhir dengan "kode ravioli"; begitu banyak potongan seukuran gigitan yang sulit dilacak untuk mencari tahu di mana sebenarnya hal-hal itu terjadi. Membagi antarmuka dengan dua metode juga tidak perlu jika semua pengguna saat ini membutuhkan kedua metode tersebut. Bahkan jika salah satu kelas dependen hanya membutuhkan salah satu dari dua metode, secara umum dapat diterima untuk tidak membagi antarmuka jika metodenya secara konseptual memiliki kohesi yang sangat tinggi (contoh yang baik adalah "metode antonim" yang merupakan pertentangan yang tepat satu sama lain).
Segregasi antarmuka harus didasarkan pada kelas yang bergantung pada antarmuka:
Jika hanya ada satu kelas yang tergantung pada antarmuka, jangan pisahkan. Jika kelas tidak menggunakan satu atau lebih metode antarmuka, dan itu adalah satu-satunya konsumen antarmuka, kemungkinan besar Anda seharusnya tidak mengekspos metode-metode itu di tempat pertama.
Jika ada lebih dari satu kelas yang bergantung pada antarmuka, dan semua tanggungan menggunakan semua metode antarmuka, jangan pisahkan; jika Anda harus mengubah antarmuka (untuk menambahkan metode atau mengubah tanda tangan), semua konsumen saat ini akan dipengaruhi oleh perubahan apakah Anda memisahkan atau tidak (meskipun jika Anda menambahkan metode yang setidaknya tidak perlu satu ketergantungan, pertimbangkan hati-hati jika perubahan itu seharusnya diimplementasikan sebagai antarmuka baru, mungkin mewarisi dari yang sudah ada).
Jika ada lebih dari satu kelas yang bergantung pada antarmuka, dan mereka tidak menggunakan semua metode yang sama, itu adalah kandidat untuk pemisahan. Lihatlah "koherensi" antarmuka; apakah semua metode memajukan satu tujuan pemrograman yang sangat spesifik? Jika Anda dapat mengidentifikasi lebih dari satu tujuan inti untuk antarmuka (dan implementornya), pertimbangkan untuk memisahkan antarmuka di sepanjang garis tersebut untuk membuat antarmuka yang lebih kecil dengan lebih sedikit "alasan untuk berubah".
sumber
IBaz : IFoo, IBar
dan mengharuskan itu.IFoo
danIBar
, mendefinisikan kompositIFooBar
mungkin merupakan ide yang baik, tetapi jika antarmuka terpecah dengan baik, mudah untuk akhirnya membutuhkan lusinan jenis antarmuka yang berbeda. Pertimbangkan koleksi fitur-fitur berikut yang mungkin dimiliki: Hitung, laporkan Hitungan, Baca elemen ke-n, Tulis elemen ke-n, Sisipkan sebelum elemen ke-n, Hapus elemen ke-n, Item baru (perbesar koleksi dan kembalikan indeks ruang baru), dan Tambah. Sembilan metode: ECRWIDNA. Saya mungkin bisa menggambarkan lusinan jenis yang secara alami akan mendukung banyak kombinasi yang berbeda.