OOP: Apa saja situasi di mana desain berbasis kelas lebih baik daripada yang berbasis antarmuka?


9

Saya sedang membaca situs web JDOM .

Mengapa API JDOM didefinisikan berdasarkan kelas konkret daripada antarmuka?

Jason Hunter merangkum argumen terhadap API berbasis antarmuka untuk JDOM:

Dengan antarmuka yang semuanya menjadi pabrik, elemen harus 'diimpor' ke dalam dokumen baru dan bukan hanya ditambahkan, fitur seperti serialisasi jangka panjang tidak dapat dijamin, dan daftarnya terus berlanjut.

Kami mulai dengan antarmuka sebenarnya. Selama peninjauan pra-rilis kami ke beberapa rekan kami menerima umpan balik kami harus mencoba kelas konkret. Kami melakukannya, dan desainnya jauh lebih baik.

Saya seorang desainer pemula. Semua saran yang saya dengar sampai sekarang menyarankan agar tidak menggunakan desain dengan kelas beton.

Mungkin menggunakan kelas beton yang sesuai di tempat-tempat tertentu. Apakah ada masalah kelas umum yang menggunakan kelas beton dalam desain oke?



Anda juga dapat melihat seri "Batasi abstraksi Anda": ayende.com/blog/153889/…
henginy

"Kami melakukannya, dan desainnya jauh lebih baik untuk itu." - bagaimana itu lebih baik?
CodeART

Jawaban:


5
  • Warisan menciptakan ketergantungan pada implementasi , yang mungkin menjadi masalah besar dalam hal pemeliharaan. Akibat dari hal ini adalah bahwa Anda dapat dengan aman menggunakan kelas warisan dan konkret ketika berhadapan dengan objek transfer data , yang menurut definisi hampir tidak mengandung implementasi. Anda juga dapat menggunakan warisan kelas konkret saat Anda menginginkan ketergantungan ini. Anda mungkin ingin menggunakan kelas abstrak yang berisi metode umum (biasanya fungsi utilitas) di bagian atas hierarki dalam situasi ini.
  • Saat menggunakan hierarki kelas yang konkret, jangan lupa untuk menerapkan Prinsip Pergantian Liskov .
  • Tidak ada masalah dengan menggunakan kelas konkret untuk klien (yaitu kelas yang menggunakan, bukan kelas yang digunakan).
  • IMHO, Anda dapat menggunakan kelas konkret sampai ada perubahan. Prinsip Terbuka / Tertutup akan memberitahu Anda untuk menggunakan antarmuka untuk menghindari penggandengan, tetapi mengenai Prinsip You Ain't Gonna Need It Anda mungkin mempertimbangkan untuk menggunakan kelas konkret sampai saat ketika Anda perlu mengubah sesuatu dalam implementasi. Masalahnya adalah Anda harus mengubah setiap klien dari kelas Anda saat pertama kali sesuatu berubah di suatu tempat. Meskipun Anda hanya memiliki satu alat yang memungkinkan untuk melakukan sesuatu, Anda dapat menggunakan kelas IMO konkret.

[EDIT] Situs web JDOM mengambil java.io.File sebagai contoh, tapi ini jelas merupakan desain berbasis antarmuka karena orang dapat memanipulasi contoh java.io.File seolah-olah itu hanya Serializable. Dalam situasi ini hanya "pencipta" yang tahu kelas konkret


Ada dua definisi "objek nilai" yang saling bertentangan. Milik Anda tampaknya kurang umum, juga dikenal sebagai "objek transfer data".
Michael Borgwardt

@MichaelBorgwardt Thx untuk menunjukkan ini karena saya tidak bermaksud "objek transfer data" saja: Saya mengedit jawaban saya
Matthias Jouan

1
LSP penting untuk setiap hubungan subtipe, implementasi antarmuka, dan juga warisan.

2

Dari situs JDOM:

Jason (Hunter) mendirikan proyek JDOM pada awal 2000 bersama dengan Brett McLaughlin

Artinya, sekitar waktu Java 1.3 diperkenalkan. Tidak ada jalan jatuh tempo dalam hal pengembangan Java - pengembang yang paling berpengalaman hanya memiliki 4 tahun menggunakan Java terbaik. Tidak ada wadah IoC yang digunakan secara luas, tidak ada Hibernate. Apache Struts baru saja memulai.

Itu semua untuk mengatakan bahwa Jason dan Brett salah. Banyak orang belum "mengerti". Jika mereka memiliki latar belakang C ++, well, Anda tidak perlu antarmuka di C ++ (well, mereka ada di C ++, tetapi Anda tidak benar-benar membutuhkannya, kan?), Mengapa sih menggunakannya di Jawa? Ya, ada banyak alasan bagus, yang bisa mengarahkan Anda ke orang lain.

Mereka jelas salah

apa pun yang bisa dilakukan dengan antarmuka dapat dilakukan dengan subclassing

Java tidak memungkinkan multiple inheritance of class, tetapi Java memungkinkan implementasi beberapa antarmuka. Itu bisa membuat perbedaan nyata.


2

Ingat, pertama, bahwa dalam Pengembangan Perangkat Lunak ada beberapa cara untuk memecahkan masalah, dan jika beberapa pengembang menggunakan teknik yang berbeda dari Anda, itu tidak berarti salah.

Salah satu kasus tersebut adalah "antarmuka" versus (basis) "kelas". Ada situasi di mana tujuan yang sama dapat dicapai dengan kedua teknik.

Untuk membuat berbagai hal, lebih rumit, ada beberapa penggunaan antarmuka, hanya untuk menyebutkan:

  • satu adalah merancang "kontrak" atau "spesifikasi" tanpa "implementasi"
  • lain untuk menambahkan fungsi ke kelas yang ada atau hierarki kelas
  • komplementer dengan sebelumnya, untuk memungkinkan akses berbagi di antara berbagai objek, teknologi, contoh: Enterprise Beans, CORBA, COM, WebServices
  • untuk meniru multiple inheritance

Pertanyaan Anda berlaku untuk poin pertama.

Saat Anda ingin mengembangkan hierarki kelas, bukan hanya satu kelas, dan beberapa kelas dimaksudkan untuk berbagi beberapa fitur tertentu, Anda mungkin ingin memulai dengan kelas dasar, bahkan jika itu dapat dilakukan dengan antarmuka.

Dan, tinggalkan antarmuka untuk skenario lain.

Contoh yang baik adalah perpustakaan widget (kontrol).

Saya sarankan, lihatlah ke bahasa pemrograman lain bagaimana mereka menggunakan antarmuka & kelas seperti: PHP, Delphi (Object Pascal), C #.

Bersulang.


0

Anda biasanya menginginkan antarmuka untuk apa pun yang dilewatkan sebagai parameter atau dikembalikan, pada dasarnya sehingga Anda dapat memisahkan kelas dari dependensinya.

JADI, jika kita mencari kelas, kita tidak pernah lulus dengan normal kecuali pengecualian muncul dalam pikiran. Saya bukan pengembang Java, tetapi tentu saja dalam bahasa lain yang serupa saya tidak berpikir saya telah melihat antarmuka yang ditentukan untuk pengecualian.


0

Aturan desain API benar-benar hal yang spesifik. Saya tidak yakin Anda harus menyimpulkan apa pun dari FAQ itu dalam hal bagaimana Anda harus merancang kode sehari-hari Anda.

Untuk kode reguler Anda, masih benar bahwa Anda akan lebih sering menggunakan antarmuka atau pewarisan kelas abstrak daripada IMO pewarisan vanilla.

Untuk mendapatkan pemahaman yang baik tentang aturan itu, Anda harus menempatkan diri Anda bukan dari sudut pandang kelas turunan vs superclassnya, tetapi dari sudut pandang suatu objek yang memiliki ketergantungan pada objek lain. Hampir selalu lebih baik untuk bergantung pada abstraksi daripada implementasi konkret karena memungkinkan Anda untuk menerima seluruh rangkaian kelas yang berbeda sebagai dependensi, bergantung pada kontrak mereka dan bukan detail implementasi mereka.

Penggunaan pertama untuk ini sering dalam unit test - jika Anda benar-benar ingin unit menguji kelas Anda dalam isolasi lengkap, Anda melakukannya terhadap implementasi palsu dari dependensi Anda yang berbeda dari implementasi nyata yang akan digunakan dalam produksi.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.