Dalam bahasa Java, kelas abstrak dan antarmuka adalah dua mekanisme yang mendukung definisi kelas abstrak. Justru karena keberadaan kedua mekanisme inilah Java diberikan kemampuan berorientasi objek yang kuat. Ada banyak kesamaan antara kelas abstrak dan antarmuka dalam hal dukungan untuk definisi kelas abstrak, dan keduanya bahkan dapat saling menggantikan satu sama lain. Oleh karena itu, banyak pengembang tampaknya lebih santai dalam memilih kelas abstrak dan antarmuka saat mendefinisikan kelas abstrak. Faktanya, masih terdapat perbedaan besar di antara keduanya. Pilihannya bahkan mencerminkan pemahaman tentang sifat domain masalah dan apakah pemahaman maksud desain sudah benar dan masuk akal. Artikel ini akan menganalisis perbedaan di antara keduanya dan mencoba memberikan dasar bagi pengembang untuk memilih di antara keduanya.
Memahami kelas abstrak
Kelas abstrak dan antarmuka keduanya digunakan untuk mendefinisikan kelas abstrak dalam bahasa Java (kelas abstrak dalam artikel ini tidak diterjemahkan dari kelas abstrak, ini mewakili badan abstrak, dan kelas abstrak digunakan untuk mendefinisikan kelas abstrak dalam bahasa Java) A metode, harap perhatikan perbedaannya), jadi apa itu kelas abstrak, dan manfaat apa yang bisa didapat dari penggunaan kelas abstrak?
Dalam konsep berorientasi objek, kita mengetahui bahwa semua objek direpresentasikan oleh kelas, namun hal sebaliknya tidak berlaku. Tidak semua kelas digunakan untuk mendeskripsikan objek. Jika suatu kelas tidak berisi informasi yang cukup untuk mendeskripsikan objek tertentu, kelas tersebut adalah kelas abstrak. Kelas abstrak sering digunakan untuk mewakili konsep-konsep abstrak yang kita peroleh dari analisis dan desain area masalah. Kelas-kelas tersebut merupakan abstraksi dari serangkaian konsep spesifik yang terlihat berbeda tetapi pada dasarnya sama. Misalnya: Jika kita mengembangkan perangkat lunak pengedit grafis, kita akan menemukan bahwa ada beberapa konsep khusus seperti lingkaran dan segitiga dalam domain masalahnya.Mereka berbeda, tetapi semuanya termasuk dalam konsep bentuk dalam domain masalah. Jika ada, itu adalah konsep abstrak. Justru karena konsep abstrak tidak memiliki konsep konkrit yang sesuai dalam domain permasalahan, sehingga kelas abstrak yang digunakan untuk merepresentasikan konsep abstrak tidak dapat dipakai.
Di bidang berorientasi objek, kelas abstrak terutama digunakan untuk menyembunyikan tipe. Kita dapat membuat deskripsi abstrak dari sekumpulan perilaku yang tetap, namun kumpulan perilaku ini dapat mempunyai sejumlah kemungkinan implementasi konkrit. Deskripsi abstrak ini adalah kelas abstrak, dan kumpulan implementasi konkrit yang mungkin diwakili oleh semua kemungkinan kelas turunan. Modul dapat beroperasi pada badan abstrak. Karena sebuah modul bergantung pada abstraksi tetap, ia tidak dapat dimodifikasi pada saat yang sama, perilaku modul ini juga dapat diperluas dengan menurunkan dari abstraksi ini. Pembaca yang akrab dengan OCP pasti tahu bahwa untuk mewujudkan OCP (Prinsip Terbuka-Tertutup), salah satu prinsip inti desain berorientasi objek, kelas abstrak adalah kuncinya.
Melihat kelas abstrak dan antarmuka dari tingkat definisi tata bahasa
Pada tingkat tata bahasa, bahasa Java menyediakan metode definisi yang berbeda untuk kelas abstrak dan antarmuka. Berikut ini adalah contoh pendefinisian kelas abstrak bernama Demo untuk menggambarkan perbedaan ini.
Cara mendefinisikan kelas abstrak Demo menggunakan kelas abstrak adalah sebagai berikut:
Demo kelas abstrak{
abstrak batal metode1();
abstrak batal metode2();
…
}
Cara mendefinisikan kelas abstrak Demo menggunakan antarmuka adalah sebagai berikut:
Demo antarmuka{
batal metode1();
batal metode2();
…
}
Dalam metode kelas abstrak, Demo dapat memiliki anggota datanya sendiri atau metode anggota non-abstrak. Dalam metode antarmuka, Demo hanya dapat memiliki anggota data statis yang tidak dapat diubah (yaitu, harus berupa final statis, tetapi data anggota umumnya tidak didefinisikan dalam antarmuka), dan semua metode anggota bersifat abstrak. Dalam arti tertentu, antarmuka adalah bentuk khusus dari kelas abstrak.
Dari perspektif pemrograman, kelas abstrak dan antarmuka dapat digunakan untuk mengimplementasikan gagasan "desain berdasarkan kontrak". Namun, masih terdapat beberapa perbedaan dalam penggunaan spesifiknya.
Pertama-tama, kelas abstrak mewakili hubungan pewarisan dalam bahasa Java, dan suatu kelas hanya dapat menggunakan hubungan warisan satu kali (karena Java tidak mendukung pewarisan berganda - catatan transfer). Namun, sebuah kelas dapat mengimplementasikan banyak antarmuka. Mungkin ini merupakan pertimbangan kompromi oleh para perancang bahasa Java ketika mempertimbangkan dukungan Java untuk pewarisan berganda.
Kedua, dalam definisi kelas abstrak, kita dapat menetapkan perilaku default metode tersebut. Namun dalam definisi antarmuka, metode tidak boleh memiliki perilaku default untuk menghindari batasan ini, delegasi harus digunakan, tetapi ini akan menambah kompleksitas dan terkadang menyebabkan banyak masalah.
Ada masalah serius lainnya karena tidak dapat mendefinisikan perilaku default di kelas abstrak, yang dapat menyebabkan masalah pemeliharaan. Karena jika nanti Anda ingin memodifikasi antarmuka kelas (biasanya diwakili oleh kelas abstrak atau antarmuka) untuk beradaptasi dengan situasi baru (misalnya menambahkan metode baru atau menambahkan parameter baru ke metode yang sudah digunakan), itu akan sangat merepotkan mungkin memakan banyak waktu (terutama jika ada banyak kelas turunan). Namun jika antarmuka diimplementasikan melalui kelas abstrak, maka Anda mungkin hanya perlu mengubah perilaku default yang ditentukan dalam kelas abstrak.
Demikian pula, jika perilaku default tidak dapat didefinisikan dalam kelas abstrak, penerapan metode yang sama akan muncul di setiap kelas turunan dari kelas abstrak, melanggar prinsip "satu aturan, satu tempat", yang mengakibatkan duplikasi kode, yang juga merugikan bagi masa depan. Oleh karena itu, berhati-hatilah saat memilih antara kelas abstrak dan antarmuka.
Melihat kelas abstrak dan antarmuka dari tingkat konsep desain
Hal di atas terutama membahas perbedaan antara kelas abstrak dan antarmuka dari sudut pandang definisi tata bahasa dan pemrograman. Perbedaan pada level ini relatif rendah dan tidak penting. Bagian ini akan menganalisis perbedaan antara kelas abstrak dan antarmuka dari tingkat lain: konsep desain tercermin dalam keduanya. Penulis percaya bahwa hanya dengan menganalisis dari level inilah kita dapat memahami esensi dari kedua konsep tersebut.
Seperti disebutkan sebelumnya, kelas abstrak mewujudkan hubungan pewarisan dalam bahasa Java agar hubungan pewarisan masuk akal, harus ada hubungan "is-a" antara kelas induk dan kelas turunan, yaitu kelas induk dan kelas turunan. kelas turunan memiliki konsep yang sama. Hal ini tidak berlaku untuk antarmuka. Pelaksana antarmuka dan definisi antarmuka tidak harus konsisten secara konseptual, namun hanya mengimplementasikan kontrak yang ditentukan oleh antarmuka. Agar pembahasannya lebih mudah dipahami, berikut akan diilustrasikan contoh sederhananya.
Perhatikan contoh berikut. Misalkan ada konsep abstrak tentang Door di domain masalah kita. Door memiliki dua tindakan: buka dan tutup metodenya adalah sebagai berikut:
Gunakan kelas abstrak untuk mendefinisikan Pintu:
pintu kelas abstrak{
abstrak batal terbuka();
abstrak batal tutup();
}
Tentukan Pintu menggunakan metode antarmuka:
antarmuka Pintu{
batal terbuka();
batal tutup();
}
Tipe Pintu spesifik lainnya dapat memperluas Pintu yang ditentukan menggunakan metode kelas abstrak atau mengimplementasikan Pintu yang ditentukan menggunakan metode antarmuka. Tampaknya tidak ada perbedaan besar antara menggunakan kelas abstrak dan antarmuka.
Jika Door sekarang diharuskan memiliki fungsi alarm. Bagaimana seharusnya kita mendesain struktur kelas untuk contoh ini (dalam contoh ini, ini terutama untuk menunjukkan perbedaan konsep desain antara kelas abstrak dan antarmuka, dan masalah lain yang tidak relevan telah disederhanakan atau diabaikan)? Kemungkinan solusi tercantum di bawah ini dan berbagai opsi ini dianalisis dari tingkat konsep desain.
Solusi satu:
Cukup tambahkan metode alarm ke definisi Pintu, sebagai berikut:
pintu kelas abstrak{
abstrak batal terbuka();
abstrak batal tutup();
abstrak batal alarm();
}
atau
antarmuka Pintu{
batal terbuka();
batal tutup();
batalkan alarm();
}
Kemudian AlarmDoor dengan fungsi alarm didefinisikan sebagai berikut:
kelas AlarmDoor memperluas Pintu{
batal terbuka(){…}
batal tutup(){…}
batalkan alarm(){…}
}
atau
kelas AlarmDoor mengimplementasikan Pintu{
batal terbuka(){…}
batal tutup(){…}
batalkan alarm(){…}
}
Metode ini melanggar ISP (Interface Segregation Principle), prinsip inti dalam desain berorientasi objek, dalam definisi Door, metode perilaku yang melekat pada konsep Door itu sendiri dicampur dengan metode perilaku dari konsep "alarm" lainnya. Salah satu permasalahan yang ditimbulkan adalah modul yang hanya mengandalkan konsep Door akan berubah karena adanya perubahan konsep "alarm" (misalnya memodifikasi parameter metode alarm), dan sebaliknya.
Solusi kedua:
Karena buka, tutup, dan alarm merupakan dua konsep yang berbeda, menurut prinsip ISP, keduanya harus didefinisikan dalam kelas abstrak yang mewakili kedua konsep ini. Metode definisinya adalah: kedua konsep didefinisikan menggunakan metode kelas abstrak; kedua konsep didefinisikan menggunakan metode antarmuka;
Jelasnya, karena bahasa Java tidak mendukung pewarisan berganda, maka tidak mungkin untuk mendefinisikan kedua konsep tersebut menggunakan kelas abstrak. Dua metode terakhir sama-sama layak, namun pilihannya mencerminkan pemahaman esensi konsep dalam domain masalah dan apakah refleksi maksud desain sudah benar dan masuk akal. Mari kita analisa dan jelaskan satu per satu.
Jika kedua konsep tersebut didefinisikan menggunakan metode antarmuka, maka hal tersebut mencerminkan dua masalah: 1. Kita mungkin tidak memahami domain masalahnya dengan jelas. Apakah AlarmDoor pada dasarnya adalah pintu atau alarm? 2. Jika tidak ada masalah dengan pemahaman kita tentang domain masalah, misalnya: melalui analisis domain masalah, kami menemukan bahwa AlarmDoor secara konseptual konsisten dengan Door, maka kami tidak akan dapat mengungkapkan maksud desain kami dengan benar saat mengimplementasikannya. , karena Definisi kedua konsep ini (keduanya didefinisikan menggunakan metode antarmuka) tidak mencerminkan makna di atas.
Jika pemahaman kita tentang domain masalahnya adalah: AlarmDoor secara konseptual pada dasarnya adalah sebuah Pintu, dan juga memiliki fungsi yang mengkhawatirkan. Bagaimana seharusnya kita merancang dan menerapkannya agar mencerminkan maksud kita dengan jelas? Seperti disebutkan sebelumnya, kelas abstrak mewakili hubungan pewarisan dalam bahasa Java, dan hubungan pewarisan pada dasarnya adalah hubungan "is-a". Jadi untuk konsep Door, kita harus menggunakan metode kelas abstrak untuk mendefinisikannya. Selain itu, AlarmDoor memiliki fungsi alarm yang artinya dapat melengkapi perilaku yang ditentukan dalam konsep alarm, sehingga konsep alarm dapat ditentukan melalui antarmuka. Seperti yang ditunjukkan di bawah ini:
pintu kelas abstrak{
abstrak batal terbuka();
abstrak batal tutup();
}
antarmukaAlarm{
batalkan alarm();
}
kelas Alarm Pintu memperluas Pintu mengimplementasikan Alarm{
batal terbuka(){…}
batal tutup(){…}
batalkan alarm(){…}
}
Metode implementasi ini pada dasarnya dapat dengan jelas mencerminkan pemahaman kita tentang domain masalah dan mengungkapkan maksud desain kita dengan benar. Faktanya, kelas abstrak mewakili hubungan "is-a", dan antarmuka mewakili hubungan "seperti-a". Anda dapat menggunakannya sebagai dasar ketika memilih Contoh: Jika kita Jika AlarmDoor pada dasarnya adalah sebuah alarm dalam konsep dan mempunyai fungsi sebagai Pintu, maka definisi di atas harus dibalik.
ringkasan
1. Kelas abstrak mewakili hubungan pewarisan dalam bahasa Java, dan suatu kelas hanya dapat menggunakan hubungan pewarisan satu kali. Namun, sebuah kelas dapat mengimplementasikan banyak antarmuka.
2. Di kelas abstrak, Anda dapat memiliki anggota data Anda sendiri, dan Anda juga dapat memiliki metode anggota non-abstrak, tetapi di antarmuka, Anda hanya dapat memiliki anggota data statis yang tidak dapat diubah (yaitu, anggota tersebut harus final statis, tetapi di antarmuka, anggota data umumnya tidak ditentukan), dan semua metode anggota bersifat abstrak.
3. Kelas abstrak dan antarmuka mencerminkan konsep desain yang berbeda. Faktanya, kelas abstrak mewakili hubungan "adalah-a", dan antarmuka mewakili hubungan "seperti-a".
4. Kelas yang mengimplementasikan kelas abstrak dan antarmuka harus mengimplementasikan semua metode di dalamnya. Kelas abstrak dapat memiliki metode non-abstrak. Tidak boleh ada metode implementasi di antarmuka.
5. Variabel yang didefinisikan dalam antarmuka adalah public static final secara default, dan nilai awalnya harus diberikan, sehingga tidak dapat didefinisikan ulang di kelas implementasi, dan nilainya juga tidak dapat diubah.
6. Variabel dalam kelas abstrak bersifat ramah secara default, dan nilainya dapat didefinisikan ulang dalam subkelas atau ditugaskan kembali.
7. Metode dalam antarmuka bertipe publik dan abstrak secara default.
sebagai kesimpulan
Kelas abstrak dan antarmuka adalah dua cara untuk mendefinisikan kelas abstrak dalam bahasa Java, dan keduanya sangat mirip. Namun, pemilihannya sering kali mencerminkan pemahaman tentang esensi konsep dalam domain masalah dan apakah refleksi dari maksud desain itu benar dan masuk akal, karena keduanya mengungkapkan hubungan yang berbeda antar konsep (walaupun semuanya dapat mencapai fungsi yang diperlukan). Ini sebenarnya semacam penggunaan bahasa idiomatis. Saya harap pembaca dapat memahaminya dengan cermat.