Saya telah melihat ini disebutkan beberapa kali dan saya tidak jelas apa artinya. Kapan dan mengapa Anda melakukan ini?
Saya tahu apa yang dilakukan antarmuka, tetapi fakta saya tidak jelas tentang hal ini membuat saya berpikir saya kehilangan menggunakannya dengan benar.
Apakah itu hanya jika Anda melakukannya:
IInterface classRef = new ObjectWhatever()
Anda bisa menggunakan kelas apa saja yang mengimplementasikan IInterface
? Kapan Anda perlu melakukan itu? Satu-satunya hal yang dapat saya pikirkan adalah jika Anda memiliki metode dan Anda tidak yakin objek apa yang akan dilewati kecuali untuk penerapannya IInterface
. Saya tidak bisa memikirkan seberapa sering Anda perlu melakukan itu.
Juga, bagaimana Anda bisa menulis metode yang mengambil objek yang mengimplementasikan antarmuka? Apakah itu mungkin?
sumber
Jawaban:
Ada beberapa jawaban indah di sini untuk pertanyaan-pertanyaan ini yang masuk ke segala macam detail besar tentang antarmuka dan kode kopling longgar, inversi kontrol dan sebagainya. Ada beberapa diskusi yang cukup memabukkan, jadi saya ingin mengambil kesempatan untuk memecah hal-hal sedikit untuk memahami mengapa antarmuka berguna.
Ketika saya pertama kali mulai terkena antarmuka, saya juga bingung tentang relevansinya. Saya tidak mengerti mengapa Anda membutuhkannya. Jika kita menggunakan bahasa seperti Java atau C #, kita sudah memiliki warisan dan saya melihat antarmuka sebagai bentuk warisan yang lebih lemah dan berpikir, "mengapa repot-repot?" Dalam arti saya benar, Anda dapat menganggap antarmuka sebagai semacam bentuk warisan yang lemah, tetapi di luar itu saya akhirnya memahami penggunaannya sebagai konstruk bahasa dengan menganggapnya sebagai alat untuk mengklasifikasikan ciri-ciri umum atau perilaku yang ditunjukkan oleh berpotensi banyak kelas objek yang tidak terkait.
Misalnya - katakan Anda memiliki permainan SIM dan memiliki kelas berikut:
Jelas, kedua benda ini tidak memiliki kesamaan dalam hal pewarisan langsung. Tapi, bisa dibilang keduanya sama-sama menyebalkan.
Katakanlah game kita perlu memiliki beberapa hal acak yang mengganggu pemain game ketika mereka makan malam. Ini bisa menjadi
HouseFly
atau satuTelemarketer
atau keduanya - tetapi bagaimana Anda mengizinkan keduanya dengan satu fungsi? Dan bagaimana Anda meminta setiap jenis objek yang berbeda untuk "melakukan hal yang mengganggu" dengan cara yang sama?Kunci untuk menyadari adalah bahwa keduanya
Telemarketer
danHouseFly
berbagi perilaku yang secara umum ditafsirkan secara longgar meskipun mereka tidak sama dalam hal pemodelan mereka. Jadi, mari kita buat antarmuka yang bisa diterapkan keduanya:Kami sekarang memiliki dua kelas yang masing-masing dapat mengganggu dengan caranya sendiri. Dan mereka tidak perlu berasal dari kelas dasar yang sama dan berbagi karakteristik inheren yang sama - mereka hanya perlu memenuhi kontrak
IPest
- bahwa kontrak itu sederhana. Anda hanya perluBeAnnoying
. Dalam hal ini, kita dapat membuat model berikut:Di sini kami memiliki ruang makan yang menerima sejumlah pengunjung dan sejumlah hama - perhatikan penggunaan antarmuka. Ini berarti bahwa di dunia kecil kita, anggota
pests
array sebenarnya bisa menjadiTelemarketer
objek atauHouseFly
objek.The
ServeDinner
metode ini disebut ketika makan malam disajikan dan orang-orang kami di ruang makan yang seharusnya untuk makan. Dalam permainan kecil kami, saat itulah hama kami melakukan tugasnya - masing-masing hama diperintahkan untuk mengganggu melaluiIPest
antarmuka. Dengan cara ini, kita dapat dengan mudah memiliki keduanyaTelemarketers
danHouseFlys
menjengkelkan dalam caranya masing-masing - kita hanya peduli bahwa kita memiliki sesuatu padaDiningRoom
objek yang merupakan hama, kita tidak benar-benar peduli apa itu dan mereka tidak dapat memiliki apa pun dalam sama dengan lainnya.Contoh pseudo-code yang sangat dibuat-buat ini (yang menyeret jauh lebih lama daripada yang saya perkirakan) hanya dimaksudkan untuk menggambarkan jenis hal yang akhirnya menyalakan lampu bagi saya dalam hal ketika kita mungkin menggunakan antarmuka. Saya mohon maaf sebelumnya atas kekonyolan dari contoh ini, tetapi saya harap itu membantu dalam pengertian Anda. Dan, yang pasti, jawaban yang diposkan lainnya yang Anda terima di sini benar-benar mencakup keseluruhan penggunaan antarmuka saat ini dalam pola desain dan metodologi pengembangan.
sumber
BeAnnoying
sebagai no-op; interface ini mungkin ada di tempat, atau di samping, antarmuka untuk hal-hal yang menjengkelkan (jika kedua interface ada, "hal-hal yang yang mengganggu" antarmuka harus mewarisi dari "hal-hal yang mungkin mengganggu" interface). Kerugian dari menggunakan antarmuka seperti itu adalah bahwa implementasi dapat terbebani dengan menerapkan sejumlah metode rintisan yang "menjengkelkan". Keuntungannya adalah ...IPest[]
referensi IPest, Anda dapat memanggilBeAnnoying()
karena mereka memiliki metode itu, sementara Anda tidak dapat memanggil metode lain tanpa gips. Namun, setiap objekBeAnnoying()
metode individu akan dipanggil.Contoh spesifik yang biasa saya berikan kepada siswa adalah bahwa mereka harus menulis
dari pada
Ini terlihat persis sama dalam program pendek, tetapi jika Anda terus menggunakan
myList
100 kali dalam program Anda, Anda dapat mulai melihat perbedaan. Deklarasi pertama memastikan bahwa Anda hanya memanggil metodemyList
yang ditentukan olehList
antarmuka (jadi tidak adaArrayList
metode khusus). Jika Anda telah memprogram ke antarmuka dengan cara ini, nanti Anda dapat memutuskan bahwa Anda benar-benar membutuhkannyadan Anda hanya perlu mengubah kode Anda di satu tempat itu. Anda sudah tahu bahwa sisa kode Anda tidak melakukan apa pun yang akan rusak dengan mengubah implementasi karena Anda memprogram ke antarmuka .
Manfaatnya bahkan lebih jelas (saya pikir) ketika Anda berbicara tentang parameter metode dan mengembalikan nilai. Ambil ini sebagai contoh:
Deklarasi metode itu mengikat Anda pada dua implementasi konkret (
ArrayList
danHashMap
). Segera setelah metode itu dipanggil dari kode lain, setiap perubahan pada tipe itu mungkin berarti Anda harus mengubah kode panggilan juga. Akan lebih baik memprogram ke antarmuka.Sekarang tidak masalah
List
Anda kembali seperti apa, atau jenis apaMap
yang diteruskan sebagai parameter. Perubahan yang Anda buat di dalamdoSomething
metode tidak akan memaksa Anda untuk mengubah kode panggilan.sumber
Pemrograman ke antarmuka mengatakan, "Saya membutuhkan fungsi ini dan saya tidak peduli dari mana asalnya."
Pertimbangkan (di Jawa),
List
antarmuka versusArrayList
danLinkedList
kelas konkret. Jika yang saya pedulikan adalah bahwa saya memiliki struktur data yang berisi banyak item data yang harus saya akses melalui iterasi, saya akan memilihList
(dan itu 99% dari waktu). Jika saya tahu bahwa saya perlu memasukkan / menghapus waktu-konstan dari kedua ujung daftar, saya mungkin memilihLinkedList
implementasi konkret (atau lebih mungkin, gunakan antarmuka Antrian ). Jika saya tahu saya perlu akses acak dengan indeks, saya akan memilihArrayList
kelas yang konkret.sumber
Menggunakan antarmuka adalah faktor utama dalam membuat kode Anda mudah diuji selain menghapus kopling yang tidak perlu antara kelas Anda. Dengan membuat antarmuka yang mendefinisikan operasi di kelas Anda, Anda memungkinkan kelas yang ingin menggunakan fungsionalitas itu kemampuan untuk menggunakannya tanpa tergantung pada kelas implementasi Anda secara langsung. Jika nanti Anda memutuskan untuk mengubah dan menggunakan implementasi yang berbeda, Anda hanya perlu mengubah bagian dari kode di mana implementasi tersebut dipakai. Sisa kode tidak perlu diubah karena tergantung pada antarmuka, bukan kelas pelaksana.
Ini sangat berguna dalam membuat unit test. Di kelas yang diuji Anda memilikinya tergantung pada antarmuka dan menyuntikkan contoh antarmuka ke kelas (atau pabrik yang memungkinkannya untuk membuat instance antarmuka sesuai kebutuhan) melalui konstruktor atau settor properti. Kelas menggunakan antarmuka yang disediakan (atau dibuat) dalam metodenya. Saat Anda menulis tes, Anda dapat mengejek atau memalsukan antarmuka dan menyediakan antarmuka yang merespons data yang dikonfigurasi dalam pengujian unit Anda. Anda dapat melakukan ini karena kelas Anda yang diuji hanya berurusan dengan antarmuka, bukan implementasi konkret Anda. Setiap kelas yang mengimplementasikan antarmuka, termasuk kelas tiruan atau palsu Anda, akan berlaku.
EDIT: Di bawah ini adalah tautan ke artikel di mana Erich Gamma membahas kutipannya, "Program ke antarmuka, bukan implementasi."
http://www.artima.com/lejava/articles/designprinciples.html
sumber
Pemrograman ke antarmuka sama sekali tidak ada hubungannya dengan antarmuka abstrak seperti yang kita lihat di Java atau .NET. Bahkan bukan konsep OOP.
Artinya adalah jangan main-main dengan internal objek atau struktur data. Gunakan Antarmuka Program Abstrak, atau API, untuk berinteraksi dengan data Anda. Di Jawa atau C # itu berarti menggunakan properti dan metode publik alih-alih akses bidang mentah. Untuk C itu berarti menggunakan fungsi bukan pointer mentah.
EDIT: Dan dengan database itu berarti menggunakan tampilan dan prosedur tersimpan daripada akses tabel langsung.
sumber
Anda harus melihat ke Inversion of Control:
Dalam skenario seperti itu, Anda tidak akan menulis ini:
Anda akan menulis sesuatu seperti ini:
Ini akan masuk ke pengaturan berbasis aturan di
container
objek, dan membangun objek aktual untuk Anda, yang bisa menjadi ObjectWh Apapun. Yang penting adalah Anda bisa mengganti aturan ini dengan sesuatu yang menggunakan tipe objek lain secara bersamaan, dan kode Anda tetap berfungsi.Jika kita meninggalkan IoC dari tabel, Anda dapat menulis kode yang mengetahui bahwa ia dapat berbicara ke objek yang melakukan sesuatu yang spesifik , tetapi tidak pada tipe objek yang mana atau bagaimana melakukannya.
Ini akan berguna ketika melewati parameter.
Adapun pertanyaan yang Anda tanda kurung "Juga, bagaimana Anda bisa menulis metode yang mengambil objek yang mengimplementasikan Antarmuka? Apakah itu mungkin?", Di C # Anda cukup menggunakan tipe antarmuka untuk tipe parameter, seperti ini:
Ini terhubung tepat ke "bicara ke objek yang melakukan sesuatu yang spesifik." Metode yang didefinisikan di atas tahu apa yang diharapkan dari objek, bahwa ia mengimplementasikan segala sesuatu di IInterface, tetapi tidak peduli jenis objek apa itu, hanya bahwa ia mematuhi kontrak, yang merupakan antarmuka.
Misalnya, Anda mungkin terbiasa dengan kalkulator dan mungkin telah menggunakan beberapa di hari-hari Anda, tetapi sebagian besar waktu semuanya berbeda. Anda, di sisi lain, tahu bagaimana kalkulator standar harus bekerja, sehingga Anda dapat menggunakan semuanya, bahkan jika Anda tidak dapat menggunakan fitur spesifik yang dimiliki masing-masing kalkulator yang tidak dimiliki oleh yang lain.
Inilah keindahan antarmuka. Anda dapat menulis sepotong kode, yang tahu bahwa itu akan mendapatkan benda-benda yang diteruskan sehingga dapat mengharapkan perilaku tertentu. Tidak peduli seseorang berteriak-teriak objek apa itu, hanya saja itu mendukung perilaku yang diperlukan.
Biarkan saya memberi Anda sebuah contoh nyata.
Kami memiliki sistem terjemahan yang dibuat khusus untuk formulir windows. Sistem ini memutar melalui kontrol pada formulir dan menerjemahkan teks di masing-masing. Sistem tahu bagaimana menangani kontrol dasar, seperti tipe kontrol-yang-memiliki-teks-properti, dan hal-hal dasar serupa, tetapi untuk apa pun dasar, itu gagal.
Sekarang, karena kontrol mewarisi dari kelas yang telah ditentukan sebelumnya yang tidak dapat kita kendalikan, kita dapat melakukan salah satu dari tiga hal berikut:
Jadi kami melakukannya. 3. Semua kontrol kami menerapkan ILocalizable, yang merupakan antarmuka yang memberi kami satu metode, kemampuan menerjemahkan "dirinya" ke dalam wadah teks / aturan terjemahan. Dengan demikian, formulir tidak perlu mengetahui jenis kontrol yang telah ditemukannya, hanya saja ia mengimplementasikan antarmuka spesifik, dan tahu bahwa ada metode di mana ia dapat memanggil untuk melokalkan kontrol.
sumber
Kode untuk Antarmuka Bukan Implementasi tidak ada hubungannya dengan Java, maupun konstruksinya Antarmuka.
Konsep ini dibawa ke menonjol dalam Pola / Geng Empat buku tetapi kemungkinan besar ada jauh sebelum itu. Konsepnya tentu ada jauh sebelum Jawa pernah ada.
Konstruk Java Interface dibuat untuk membantu ide ini (antara lain), dan orang-orang menjadi terlalu fokus pada konstruk sebagai pusat makna daripada maksud aslinya. Namun, itu adalah alasan kami memiliki metode dan atribut publik dan pribadi di Java, C ++, C #, dll.
Itu berarti hanya berinteraksi dengan objek atau antarmuka publik sistem. Jangan khawatir atau bahkan mengantisipasi bagaimana melakukan apa yang dilakukannya secara internal. Jangan khawatir tentang penerapannya. Dalam kode berorientasi objek, itu sebabnya kami memiliki metode / atribut publik vs. pribadi. Kami dimaksudkan untuk menggunakan metode publik karena metode pribadi hanya ada untuk digunakan secara internal, di dalam kelas. Mereka membuat implementasi kelas dan dapat diubah sesuai kebutuhan tanpa mengubah antarmuka publik. Asumsikan bahwa mengenai fungsionalitas, metode pada kelas akan melakukan operasi yang sama dengan hasil yang diharapkan setiap kali Anda menyebutnya dengan parameter yang sama. Hal ini memungkinkan penulis untuk mengubah cara kerja kelas, implementasinya, tanpa memutuskan bagaimana orang berinteraksi dengannya.
Dan Anda dapat memprogram ke antarmuka, bukan implementasi tanpa pernah menggunakan antarmuka Interface. Anda dapat memprogram ke antarmuka bukan implementasi di C ++, yang tidak memiliki konstruksi Antarmuka. Anda dapat mengintegrasikan dua sistem perusahaan besar jauh lebih kuat selama mereka berinteraksi melalui antarmuka publik (kontrak) daripada memanggil metode pada objek internal ke sistem. Antarmuka diharapkan untuk selalu bereaksi dengan cara yang diharapkan karena diberikan parameter input yang sama; jika diimplementasikan ke antarmuka dan bukan implementasi. Konsep ini bekerja di banyak tempat.
Goyang pikiran bahwa Java Interfaces ada hubungannya dengan konsep 'Program ke Antarmuka, Bukan Implementasi'. Mereka dapat membantu menerapkan konsep tersebut, tetapi mereka bukan konsepnya.
sumber
Sepertinya Anda mengerti bagaimana antarmuka bekerja tetapi tidak yakin kapan menggunakannya dan keuntungan apa yang mereka tawarkan. Berikut adalah beberapa contoh kapan antarmuka akan masuk akal:
maka saya bisa membuat GoogleSearchProvider, YahooSearchProvider, LiveSearchProvider, dll.
lalu buat JpegImageLoader, GifImageLoader, PngImageLoader, dll.
Sebagian besar sistem add-in dan plugin bekerja di luar antarmuka.
Penggunaan populer lainnya adalah untuk pola Repositori. Katakanlah saya ingin memuat daftar kode pos dari berbagai sumber
maka saya bisa membuat XMLZipCodeRepository, SQLZipCodeRepository, CSVZipCodeRepository, dll. Untuk aplikasi web saya, saya sering membuat repositori XML sejak awal sehingga saya bisa mendapatkan sesuatu dan menjalankan sebelum Database SQL siap. Setelah database siap, saya menulis SQLRepository untuk menggantikan versi XML. Sisa kode saya tetap tidak berubah karena hanya berjalan dari antarmuka.
Metode dapat menerima antarmuka seperti:
sumber
Itu membuat kode Anda jauh lebih mudah dikembangkan dan dapat dipertahankan ketika Anda memiliki set kelas yang sama. Saya seorang programmer junior, jadi saya bukan ahli, tetapi saya baru saja menyelesaikan sebuah proyek yang membutuhkan sesuatu yang serupa.
Saya bekerja pada perangkat lunak sisi klien yang berbicara ke server yang menjalankan perangkat medis. Kami sedang mengembangkan versi baru perangkat ini yang memiliki beberapa komponen baru yang kadang-kadang harus dikonfigurasikan oleh pelanggan. Ada dua jenis komponen baru, dan mereka berbeda, tetapi mereka juga sangat mirip. Pada dasarnya, saya harus membuat dua bentuk konfigurasi, dua daftar kelas, dua segalanya.
Saya memutuskan bahwa akan lebih baik untuk membuat kelas dasar abstrak untuk setiap jenis kontrol yang akan menampung hampir semua logika nyata, dan kemudian jenis turunan untuk mengurus perbedaan antara dua komponen. Namun, kelas dasar tidak akan dapat melakukan operasi pada komponen ini jika saya harus khawatir tentang tipe sepanjang waktu (well, mereka bisa saja melakukannya, tetapi akan ada pernyataan "jika" atau beralih di setiap metode) .
Saya mendefinisikan antarmuka sederhana untuk komponen-komponen ini dan semua kelas dasar berbicara dengan antarmuka ini. Sekarang ketika saya mengubah sesuatu, itu cukup 'hanya berfungsi' di mana-mana dan saya tidak memiliki duplikasi kode.
sumber
Banyak penjelasan di luar sana, tetapi untuk membuatnya lebih sederhana. Ambil contoh a
List
. Seseorang dapat mengimplementasikan daftar dengan sebagai:Dengan membuat antarmuka, ucapkan a
List
. Anda hanya kode untuk definisi Daftar atau apaList
artinya dalam kenyataan.Anda dapat menggunakan jenis implementasi apa pun secara internal mengatakan suatu
array
implementasi. Tapi misalkan Anda ingin mengubah implementasi karena alasan tertentu katakanlah bug atau kinerja. Maka Anda hanya perlu mengubah deklarasiList<String> ls = new ArrayList<String>()
menjadiList<String> ls = new LinkedList<String>()
.Di tempat lain dalam kode, Anda harus mengubah apa pun; Karena semuanya dibangun berdasarkan definisi
List
.sumber
Jika Anda memprogram di Java, JDBC adalah contoh yang bagus. JDBC mendefinisikan satu set antarmuka tetapi tidak mengatakan apa-apa tentang implementasi. Aplikasi Anda dapat ditulis terhadap set antarmuka ini. Secara teori, Anda memilih beberapa driver JDBC dan aplikasi Anda hanya akan berfungsi. Jika Anda menemukan ada driver JDBC lebih cepat atau "lebih baik" atau lebih murah atau untuk alasan apa pun, Anda dapat secara teori mengkonfigurasi ulang file properti Anda, dan tanpa harus membuat perubahan dalam aplikasi Anda, aplikasi Anda masih akan berfungsi.
sumber
Pemrograman ke Antarmuka mengagumkan, mempromosikan kopling longgar. Seperti @lassevk sebutkan, Inversion of Control adalah penggunaan yang bagus untuk ini.
Selain itu, lihatlah ke kepala sekolah SOLID . di sini adalah seri video
Ia melewati hard coded (contoh sangat berpasangan) kemudian melihat antarmuka, akhirnya berkembang menjadi alat IoC / DI (NInject)
sumber
Saya terlambat datang ke pertanyaan ini, tetapi saya ingin menyebutkan di sini bahwa baris "Program ke antarmuka, bukan implementasi" memiliki beberapa diskusi yang baik dalam buku Pola Desain GoF (Gang of Four).
Disebutkan, pada hal. 18:
dan di atas itu, dimulai dengan:
Jadi dengan kata lain, jangan tuliskan kelas Anda sehingga memiliki
quack()
metode untuk bebek, dan kemudianbark()
metode untuk anjing, karena mereka terlalu spesifik untuk implementasi kelas tertentu (atau subkelas). Alih-alih, tulis metode menggunakan nama yang cukup umum untuk digunakan di kelas dasar, sepertigiveSound()
ataumove()
, sehingga mereka dapat digunakan untuk bebek, anjing, atau bahkan mobil, dan kemudian klien dari kelas Anda dapat mengatakan.giveSound()
daripada memikirkan apakah akan menggunakanquack()
ataubark()
atau bahkan menentukan jenisnya sebelum mengeluarkan pesan yang benar untuk dikirim ke objek.sumber
Selain jawaban yang sudah dipilih (dan berbagai posting informatif di sini), saya akan sangat menyarankan untuk mengambil salinan Pola Desain Kepala Pertama . Ini adalah bacaan yang sangat mudah dan akan menjawab pertanyaan Anda secara langsung, menjelaskan mengapa itu penting, dan menunjukkan kepada Anda banyak pola pemrograman yang dapat Anda gunakan untuk memanfaatkan prinsip itu (dan lainnya).
sumber
Untuk menambah posting yang ada, kadang-kadang pengkodean ke antarmuka membantu proyek-proyek besar ketika pengembang bekerja pada komponen yang terpisah secara bersamaan. Yang Anda butuhkan hanyalah mendefinisikan antarmuka di muka dan menulis kode kepada mereka sementara pengembang lain menulis kode ke antarmuka yang Anda laksanakan.
sumber
Ini juga baik untuk Pengujian Unit, Anda dapat menyuntikkan kelas Anda sendiri (yang memenuhi persyaratan antarmuka) ke dalam kelas yang bergantung padanya
sumber
Dapat menguntungkan untuk memprogram ke antarmuka, bahkan ketika kita tidak bergantung pada abstraksi.
Pemrograman ke antarmuka memaksa kita untuk menggunakan subset objek yang sesuai secara kontekstual . Itu membantu karena:
Misalnya, pertimbangkan
Person
kelas yang mengimplementasikanFriend
danEmployee
antarmuka.Dalam konteks ulang tahun orang tersebut, kami memprogram ke
Friend
antarmuka, untuk mencegah memperlakukan orang tersebut sepertiEmployee
.Dalam konteks pekerjaan orang tersebut, kami memprogram ke
Employee
antarmuka, untuk mencegah batas-batas tempat kerja yang kabur.Bagus. Kami telah berperilaku dengan tepat dalam konteks yang berbeda, dan perangkat lunak kami berfungsi dengan baik.
Jauh di masa depan, jika bisnis kita berubah untuk bekerja dengan anjing, kita dapat mengubah perangkat lunak dengan cukup mudah. Pertama, kita membuat
Dog
kelas yang mengimplementasikan keduanyaFriend
danEmployee
. Lalu, kami beralih dengan amannew Person()
kenew Dog()
. Sekalipun kedua fungsi memiliki ribuan baris kode, pengeditan sederhana itu akan berfungsi karena kita tahu yang berikut ini benar:party
hanya menggunakanFriend
subset dariPerson
.workplace
hanya menggunakanEmployee
subset dariPerson
.Dog
mengimplementasikanFriend
danEmployee
antarmuka.Di sisi lain, jika salah satu
party
atauworkplace
diprogram terhadapPerson
, akan ada risiko keduanya memilikiPerson
kode-spesifik. Mengubah dariPerson
menjadiDog
akan mengharuskan kita untuk menyisir kode untuk membasmi habis-Person
spesifik kode yangDog
tidak mendukung.Moral : pemrograman ke antarmuka membantu kode kita berperilaku dengan tepat dan siap untuk perubahan. Itu juga menyiapkan kode kita untuk bergantung pada abstraksi, yang membawa lebih banyak keuntungan.
sumber
Jika saya menulis kelas baru
Swimmer
untuk menambahkan fungsionalitasswim()
dan perlu menggunakan objek kelas katakanDog
, danDog
kelas ini mengimplementasikan antarmukaAnimal
yang menyatakanswim()
.Di bagian atas hierarki (
Animal
), sangat abstrak sedangkan di bagian bawah (Dog
) sangat konkret. Cara saya berpikir tentang "pemrograman untuk antarmuka" adalah bahwa, ketika saya menulisSwimmer
kelas, saya ingin menulis kode saya terhadap antarmuka yang sejauh ini hierarki yang dalam hal ini adalahAnimal
objek. Antarmuka bebas dari detail implementasi dan dengan demikian membuat kode Anda secara longgar digabungkan.Detail implementasi dapat diubah dengan waktu, namun, itu tidak akan mempengaruhi kode yang tersisa karena semua yang Anda berinteraksi dengan antarmuka dan bukan implementasi. Anda tidak peduli seperti apa implementasinya ... yang Anda tahu adalah bahwa akan ada kelas yang akan mengimplementasikan antarmuka.
sumber
Jadi, hanya untuk mendapatkan ini dengan benar, keuntungan dari antarmuka adalah bahwa saya dapat memisahkan pemanggilan metode dari kelas tertentu. Alih-alih membuat instance antarmuka, di mana implementasinya diberikan dari kelas mana pun yang saya pilih yang mengimplementasikan antarmuka itu. Dengan demikian memungkinkan saya untuk memiliki banyak kelas, yang memiliki fungsionalitas yang serupa tetapi sedikit berbeda dan dalam beberapa kasus (kasus-kasus yang terkait dengan maksud antarmuka) tidak peduli objek mana itu.
Sebagai contoh, saya bisa memiliki antarmuka gerakan. Metode yang membuat sesuatu 'bergerak' dan objek apa pun (Orang, Mobil, Kucing) yang mengimplementasikan antarmuka gerakan dapat dilewati dan disuruh bergerak. Tanpa metode setiap mengetahui jenis kelas itu.
sumber
Bayangkan Anda memiliki produk yang disebut 'Zebra' yang dapat diperpanjang oleh plugin. Ia menemukan plugin dengan mencari DLL di beberapa direktori. Itu memuat semua DLL dan menggunakan refleksi untuk menemukan kelas yang menerapkan
IZebraPlugin
, dan kemudian memanggil metode antarmuka itu untuk berkomunikasi dengan plugin.Ini membuatnya benar-benar independen dari kelas plugin tertentu - tidak peduli apa kelasnya. Itu hanya peduli bahwa mereka memenuhi spesifikasi antarmuka.
Antarmuka adalah cara untuk menentukan titik-titik ekstensibilitas seperti ini. Kode yang berbicara ke antarmuka lebih longgar digabungkan - pada kenyataannya tidak digabungkan sama sekali dengan kode spesifik lainnya. Itu dapat beroperasi dengan plugin yang ditulis bertahun-tahun kemudian oleh orang-orang yang belum pernah bertemu pengembang asli.
Anda bisa menggunakan kelas dasar dengan fungsi virtual - semua plugin akan diturunkan dari kelas dasar. Tetapi ini jauh lebih membatasi karena suatu kelas hanya dapat memiliki satu kelas dasar, sedangkan itu dapat mengimplementasikan sejumlah antarmuka.
sumber
Penjelasan C ++.
Pikirkan sebuah antarmuka sebagai metode umum kelas Anda.
Anda kemudian dapat membuat templat yang 'tergantung' pada metode publik ini untuk menjalankan fungsinya sendiri (ini membuat panggilan fungsi didefinisikan dalam antarmuka publik kelas). Katakanlah templat ini adalah wadah, seperti kelas Vektor, dan antarmuka yang digunakannya adalah algoritma pencarian.
Setiap kelas algoritme yang mendefinisikan fungsi / antarmuka yang dibuat oleh Vector akan memenuhi 'kontrak' (seperti yang dijelaskan seseorang dalam balasan asli). Algoritma bahkan tidak perlu dari kelas dasar yang sama; satu-satunya persyaratan adalah bahwa fungsi / metode yang bergantung pada Vector (antarmuka) didefinisikan dalam algoritma Anda.
Inti dari semua ini adalah bahwa Anda dapat menyediakan berbagai algoritma / kelas pencarian yang berbeda asalkan itu menyediakan antarmuka yang bergantung pada Vector (pencarian gelembung, pencarian sekuensial, pencarian cepat).
Anda mungkin juga ingin merancang wadah lain (daftar, antrian) yang akan memanfaatkan algoritma pencarian yang sama dengan Vector dengan meminta mereka memenuhi antarmuka / kontrak yang bergantung pada algoritma pencarian Anda.
Ini menghemat waktu (prinsip OOP 'code reuse') karena Anda dapat menulis algoritme satu kali, bukan lagi, lagi dan lagi, spesifik untuk setiap objek baru yang Anda buat tanpa terlalu memperumit masalah dengan pohon warisan yang tumbuh terlalu besar.
Adapun 'ketinggalan' tentang bagaimana hal-hal beroperasi; big-time (setidaknya dalam C ++), karena ini adalah bagaimana sebagian besar kerangka kerja Perpustakaan TEMPLATE Standar beroperasi.
Tentu saja ketika menggunakan kelas inheritance dan abstrak, metodologi pemrograman untuk suatu antarmuka berubah; tetapi prinsipnya sama, fungsi / metode publik Anda adalah antarmuka kelas Anda.
Ini adalah topik besar dan salah satu prinsip dasar Pola Desain.
sumber
Di Jawa, semua kelas konkret ini mengimplementasikan antarmuka CharSequence:
Kelas-kelas konkret ini tidak memiliki kelas induk yang sama selain Object, jadi tidak ada yang menghubungkannya, selain fakta bahwa mereka masing-masing ada hubungannya dengan array karakter, mewakili, atau memanipulasi seperti itu. Misalnya, karakter String tidak dapat diubah setelah objek String dipakai, sedangkan karakter StringBuffer atau StringBuilder dapat diedit.
Namun masing-masing kelas ini mampu mengimplementasikan metode antarmuka CharSequence dengan tepat:
Dalam beberapa kasus, kelas perpustakaan kelas Java yang dulu menerima String telah direvisi untuk sekarang menerima antarmuka CharSequence. Jadi, jika Anda memiliki instance dari StringBuilder, alih-alih mengekstraksi objek String (yang berarti instantiating instance objek baru), ia dapat hanya meneruskan StringBuilder itu sendiri ketika mengimplementasikan antarmuka CharSequence.
Antarmuka yang dapat ditambahkan yang diterapkan beberapa kelas memiliki banyak manfaat yang sama untuk situasi apa pun di mana karakter dapat ditambahkan ke instance instance objek kelas beton yang mendasarinya. Semua kelas konkret ini mengimplementasikan antarmuka yang dapat ditambahkan:
sumber
CharSequence
sangat anemia. Saya berharap Java dan .NET telah memungkinkan antarmuka untuk memiliki implementasi default, sehingga orang tidak akan pare down interface murni untuk tujuan meminimalkan kode boilerplate. Dengan adanyaCharSequence
implementasi yang sah, seseorang dapat meniru sebagian besar fungsiString
dengan hanya menggunakan empat metode di atas, tetapi banyak implementasi dapat melakukan fungsi-fungsi itu jauh lebih efisien dengan cara lain. Sayangnya, bahkan jika implementasi tertentuCharSequence
menyimpan semuanya dalam satuchar[]
dan dapat melakukan banyak ...indexOf
cepat, tidak mungkin penelepon yang tidak terbiasa dengan implementasi tertentuCharSequence
dapat memintanya untuk melakukannya daripada harus digunakancharAt
untuk memeriksa setiap karakter individu.Cerpen: Seorang tukang pos diminta pulang setelah pulang dan menerima sampul berisi (surat, dokumen, cek, kartu hadiah, lamaran, surat cinta) dengan alamat yang tertulis untuk dikirimkan.
Misalkan tidak ada penutup dan meminta tukang pos untuk pulang setelah rumah dan menerima semua barang dan mengirimkannya ke orang lain, tukang pos bisa bingung.
Jadi lebih baik bungkus dengan sampul (dalam cerita kami itu adalah antarmuka) maka dia akan melakukan tugasnya dengan baik.
Sekarang tugas tukang pos adalah untuk menerima dan mengirimkan sampul saja (dia tidak akan repot dengan apa yang ada di dalam sampul).
Buat jenis yang
interface
bukan tipe aktual, tetapi implementasikan dengan tipe aktual.Untuk membuat ke antarmuka berarti komponen Anda masuk ke dalam sisa kode dengan mudah
Saya memberi Anda sebuah contoh.
Anda memiliki antarmuka AirPlane seperti di bawah ini.
Misalkan Anda memiliki metode di kelas Controller Anda seperti Planes
dan
diimplementasikan dalam program Anda. Itu tidak akan BREAK kode Anda. Maksud saya, tidak perlu berubah selama menerima argumen sebagai
AirPlane
.Karena akan menerima Airplane apapun meskipun jenis sebenarnya,
flyer
,highflyr
,fighter
, dllJuga, dalam koleksi:
List<Airplane> plane;
// Akan mengambil semua pesawatmu.Contoh berikut akan menghapus pemahaman Anda.
Anda memiliki pesawat tempur yang mengimplementasikannya, jadi
Hal yang sama untuk HighFlyer dan clasess lainnya:
Sekarang pikirkan kelas controller Anda menggunakan
AirPlane
beberapa kali,Misalkan kelas Controller Anda adalah ControlPlane seperti di bawah ini,
Di sini keajaiban datang karena Anda dapat membuat
AirPlane
instance tipe baru Anda sebanyak yang Anda inginkan dan Anda tidak mengubah kodeControlPlane
kelas.Anda dapat menambahkan sebuah instance ...
Anda juga dapat menghapus instance dari tipe yang dibuat sebelumnya.
sumber
Antarmuka seperti kontrak, di mana Anda ingin kelas implementasi Anda menerapkan metode yang tertulis dalam kontrak (antarmuka). Karena Java tidak menyediakan multiple inheritance, "pemrograman ke antarmuka" adalah cara yang baik untuk mencapai multiple inheritance.
Jika Anda memiliki kelas A yang sudah memperpanjang beberapa kelas B lain, tetapi Anda ingin kelas A juga mengikuti pedoman tertentu atau menerapkan kontrak tertentu, maka Anda dapat melakukannya dengan strategi "pemrograman untuk antarmuka".
sumber
Catatan: Kami tidak dapat membuat instance antarmuka yang tidak diimplementasikan oleh kelas - Benar.
Catatan: Sekarang kita bisa mengerti apa yang terjadi jika Bclass dan Cclass menerapkan Dintf yang sama.
Apa yang kita miliki: Prototipe antarmuka yang sama (nama fungsi dalam antarmuka), dan sebut implementasi yang berbeda.
Daftar Pustaka: Prototipe - wikipedia
sumber
Program ke antarmuka memungkinkan untuk mengubah implementasi kontrak yang ditentukan oleh antarmuka dengan mulus. Ini memungkinkan sambungan longgar antara kontrak dan implementasi spesifik.
Lihatlah pertanyaan SE ini sebagai contoh yang bagus.
Mengapa antarmuka untuk kelas Java lebih disukai?
Iya. Ini akan memiliki sedikit overhead kinerja dalam sub-detik. Tetapi jika aplikasi Anda memiliki persyaratan untuk mengubah implementasi antarmuka secara dinamis, jangan khawatir tentang dampak kinerja.
Jangan mencoba untuk menghindari beberapa implementasi antarmuka jika aplikasi Anda membutuhkannya. Dengan tidak adanya kopling antarmuka yang ketat dengan satu implementasi spesifik, Anda mungkin harus menggunakan tambalan untuk mengubah satu implementasi ke implementasi lainnya.
Satu kasus penggunaan yang baik: Penerapan pola Strategi:
Contoh Dunia Nyata dari Pola Strategi
sumber
Program ke antarmuka adalah istilah dari buku GOF. saya tidak akan langsung mengatakan itu berkaitan dengan antarmuka java melainkan antarmuka nyata. untuk mencapai pemisahan lapisan bersih, Anda perlu membuat beberapa pemisahan antara sistem misalnya: Katakanlah Anda memiliki database konkret yang ingin Anda gunakan, Anda tidak akan pernah "memprogram ke basis data", sebaliknya Anda akan "memprogram ke antarmuka penyimpanan". Anda juga tidak akan pernah "memprogram ke Layanan Web" melainkan Anda akan memprogram ke "antarmuka klien". ini agar Anda dapat dengan mudah bertukar segalanya.
Saya menemukan aturan ini membantu saya:
1 . kami menggunakan antarmuka java ketika kami memiliki beberapa jenis objek. jika saya hanya memiliki satu objek, saya tidak mengerti intinya. jika setidaknya ada dua implementasi konkret dari beberapa ide, maka saya akan menggunakan antarmuka java.
2 . jika seperti yang saya nyatakan di atas, Anda ingin membawa decoupling dari sistem eksternal (sistem penyimpanan) ke sistem Anda sendiri (DB lokal) kemudian juga menggunakan antarmuka.
perhatikan bagaimana ada dua cara untuk mempertimbangkan kapan menggunakannya. semoga ini membantu.
sumber
Saya juga melihat banyak jawaban yang bagus dan jelas di sini, jadi saya ingin memberikan sudut pandang saya di sini, termasuk beberapa informasi tambahan apa yang saya perhatikan ketika menggunakan metode ini.
Pengujian unit
Selama dua tahun terakhir, saya telah menulis proyek hobi dan saya tidak menulis unit test untuknya. Setelah menulis sekitar 50 ribu baris, saya tahu akan perlu untuk menulis unit test. Saya tidak menggunakan antarmuka (atau sangat hemat) ... dan ketika saya melakukan tes unit pertama saya, saya menemukan itu rumit. Mengapa?
Karena saya harus membuat banyak instance kelas, digunakan untuk input sebagai variabel dan / atau parameter kelas. Jadi tes lebih mirip tes integrasi (harus membuat 'kerangka kerja' kelas yang lengkap karena semuanya terikat bersama).
Takut pada antarmuka Jadi saya memutuskan untuk menggunakan antarmuka. Ketakutan saya adalah bahwa saya harus mengimplementasikan semua fungsionalitas di mana-mana (di semua kelas yang digunakan) beberapa kali. Dalam beberapa hal ini benar, namun, dengan menggunakan warisan itu dapat dikurangi banyak.
Kombinasi antarmuka dan warisan saya menemukan kombinasi ini sangat bagus untuk digunakan. Saya memberikan contoh yang sangat sederhana.
Dengan cara ini menyalin kode tidak diperlukan, sementara masih memiliki manfaat menggunakan mobil sebagai antarmuka (ICar).
sumber
Mari kita mulai dengan beberapa definisi pertama:
Antarmuka n.Himpunan semua tanda tangan yang didefinisikan oleh operasi objek disebut antarmuka ke objek
Ketik n.Antarmuka tertentu
Sebuah contoh sederhana dari antarmuka seperti yang didefinisikan di atas akan menjadi semua metode PDO objek seperti
query()
,commit()
,close()
dll, secara keseluruhan, tidak secara terpisah. Metode-metode ini, yaitu antarmuka yang mendefinisikan set lengkap pesan, permintaan yang dapat dikirim ke objek.Sebuah tipe seperti didefinisikan di atas adalah antarmuka tertentu. Saya akan menggunakan antarmuka bentuk yang dibuat-buat untuk menunjukkan:
draw()
,getArea()
,getPerimeter()
dll ..Jika suatu objek bertipe Basis Data, maksudnya ia menerima pesan / permintaan antarmuka basis data
query()
,commit()
dll. Objek dapat terdiri dari banyak jenis. Anda dapat memiliki objek database dari jenis bentuk asalkan mengimplementasikan antarmuka, dalam hal ini akan menjadi sub-mengetik .Banyak objek dapat memiliki banyak antarmuka / tipe yang berbeda dan mengimplementasikan antarmuka tersebut secara berbeda. Ini memungkinkan kita untuk mengganti objek, membiarkan kita memilih yang mana yang akan digunakan. Juga dikenal sebagai polimorfisme.
Klien hanya akan menyadari antarmuka dan bukan implementasinya.
Jadi dalam pemrograman intinya untuk sebuah antarmuka akan melibatkan membuat beberapa jenis kelas abstrak seperti
Shape
dengan antarmuka hanya ditentukan yaitudraw()
,getCoordinates()
,getArea()
dll .. Dan kemudian memiliki kelas beton yang berbeda mengimplementasikan interface yang seperti kelas Circle, kelas Square, kelas Segitiga. Oleh karena itu program ke antarmuka bukan implementasi.sumber
"Program untuk antarmuka" berarti tidak menyediakan kode keras dengan benar, artinya kode Anda harus diperpanjang tanpa merusak fungsi sebelumnya. Hanya ekstensi, bukan pengeditan kode sebelumnya.
sumber