Antarmuka (interface) adalah deklarasi kumpulan anggota tanpa badan yang berperan sebagai kontrak, sedangkan kelas yang mengikat dirinya pada kontrak itu wajib menyediakan seluruh implementasinya. Topik ini membahas pernyataan Interface, pengikatan dengan klausa Implements, serta polimorfisme yang muncul ketika objek dari kelas berbeda diproses melalui satu variabel bertipe antarmuka. Contoh yang dijalankan mendefinisikan antarmuka IPenyimpanData dengan dua kelas penyimpan yang berbeda cara kerjanya, lalu memproses keduanya dalam satu perulangan yang sama.
Kontrak tanpa implementasi#
Pernyataan Interface NamaAntarmuka mendeklarasikan daftar anggota yang hanya berupa kepala prosedur, yaitu Sub, Function, Property, dan Event tanpa isi apa pun. Antarmuka tidak menyimpan keadaan, tidak memiliki field, dan tidak pernah menjalankan kode sendiri, sehingga semuanya diserahkan kepada kelas yang mengimplementasikannya. Konvensi penamaan yang lazim memberi awalan I pada antarmuka, seperti IPenyimpanData, untuk membedakannya dari nama kelas pada pembacaan kode.
Kelas menyatakan keikutsertaannya dengan klausa Implements NamaAntarmuka setelah baris Class, dan setiap anggota antarmuka wajib dipasangkan dengan satu anggota kelas melalui sufiks Implements NamaAntarmuka.NamaAnggota. Keterikatan ini diperiksa compiler, sehingga kelas yang kehilangan satu anggota kontrak langsung ditolak pada waktu kompilasi, tanpa menunggu error muncul ketika program berjalan. Kontrak semacam ini berguna ketika beberapa kelas dengan cara kerja yang benar-benar berbeda harus melayani pemanggil yang sama.
Mengimplementasikan antarmuka pada dua kelas#
Program berikut memuat antarmuka IPenyimpanData beserta dua kelas implementasinya. PenyimpanBerkas menghitung total karakter yang diterimanya, sedangkan PenyimpanMemori menghitung jumlah catatan yang diterimanya. Kedua kelas mengikuti kontrak yang sama, tetapi cara menyimpannya sama sekali berbeda, dan perbedaan itu tidak terlihat oleh kode yang memanggilnya.
Interface IPenyimpanData
Sub Simpan(judul As String, isi As String)
Function Ringkasan() As String
End Interface
Class PenyimpanBerkas
Implements IPenyimpanData
Private jumlahKarakter As Integer
Public Sub Simpan(judul As String, isi As String) Implements IPenyimpanData.Simpan
jumlahKarakter += judul.Length + isi.Length
End Sub
Public Function Ringkasan() As String Implements IPenyimpanData.Ringkasan
Return $"berkas teks: {jumlahKarakter} karakter tercatat"
End Function
End Class
Class PenyimpanMemori
Implements IPenyimpanData
Private jumlahCatatan As Integer
Public Sub Simpan(judul As String, isi As String) Implements IPenyimpanData.Simpan
jumlahCatatan += 1
End Sub
Public Function Ringkasan() As String Implements IPenyimpanData.Ringkasan
Return $"memori proses: {jumlahCatatan} catatan tercatat"
End Function
End Class
Module Program
Sub Main()
Dim berkas As New PenyimpanBerkas()
Dim memori As New PenyimpanMemori()
' dua tipe berbeda dipanggil melalui satu tipe antarmuka yang sama
Dim target() As IPenyimpanData = {berkas, memori}
For Each penyimpan As IPenyimpanData In target
penyimpan.Simpan("Laporan Piket", "Piket sore: Dewi")
Console.WriteLine(penyimpan.Ringkasan())
Next
End Sub
End Moduleberkas teks: 29 karakter tercatat
memori proses: 1 catatan tercatatKeluaran menunjukkan dua laporan berbeda dari satu perulangan yang sama. Pada iterasi pertama, variabel penyimpan menampung objek PenyimpanBerkas, sehingga Simpan menambah jumlah karakter dan Ringkasan melaporkan 29 karakter. Jumlah itu berasal dari judul 13 karakter ditambah isi 16 karakter. Pada iterasi kedua, variabel yang sama menampung PenyimpanMemori, sehingga Simpan menambah satu pada hitungan catatan. Nama prosedur yang dipanggil identik, tetapi badan yang dijalankan mengikuti kelas objeknya.
' tidak-dijalankan
Class PenyimpanBerkas
Implements IPenyimpanData
Public Sub Simpan(judul As String, isi As String)
' error BC30149: kelas wajib mengimplementasikan anggota antarmukanya
End Sub
End ClassFragment di atas memperlihatkan kegagalan yang paling sering terjadi, yaitu kepala prosedur sudah ditulis dengan benar tetapi sufiks Implements IPenyimpanData.Simpan tertinggal. Tanpa sufiks itu compiler tidak menganggap keduanya berpasangan, dan pesan error BC30149 menuntut kelas mengimplementasikan anggota antarmukanya. Perbaikannya cukup menambahkan sufiks pada baris deklarasinya.
Polimorfisme melalui tipe antarmuka#
Variabel yang bertipe antarmuka dapat menampung objek dari kelas mana pun yang mengimplementasikannya. Pada program, array target() As IPenyimpanData menampung PenyimpanBerkas dan PenyimpanMemori sekaligus, dan perulangan For Each memanggil Simpan serta Ringkasan tanpa mengetahui kelas aslinya. Inilah polimorfisme (polymorphism) melalui antarmuka, yaitu satu tipe kontrak yang berlaku untuk banyak wujud implementasi.
Keuntungan dari pemisahan ini terasa ketika implementasi baru ditambahkan. Kelas PenyimpanArsip yang juga mengimplementasikan IPenyimpanData dapat disisipkan ke array target tanpa mengubah satu baris perulangan, karena perulangan hanya bergantung pada kontrak dan bukan pada daftar kelasnya. Pemanggil yang hanya melihat tipe IPenyimpanData pun terlindungi dari perubahan internal, sehingga kode yang memenuhi kontrak dan kode yang menggunakannya dapat berkembang terpisah.
Antarmuka dan pewarisan kelas#
Antarmuka dan pewarisan kelas melengkapi satu sama lain dan bekerja pada sumber yang berbeda. Pewarisan kelas mewariskan implementasi siap pakai dari satu kelas induk, sedangkan antarmuka hanya menjanjikan bentuk anggota dan boleh diambil lebih dari satu. Satu kelas VB.NET boleh mewarisi satu kelas induk sekaligus mengimplementasikan beberapa antarmuka, sehingga kemampuan dari beberapa kontrak dapat dikumpulkan pada satu kelas tanpa melanggar larangan pewarisan ganda.
Pilihan antara keduanya mengikuti kebutuhan. Apabila turunan perlu mewarisi logika yang sudah jadi dari induknya, pewarisan kelas adalah pilihan yang tepat, sedangkan jika yang dibutuhkan hanyalah janji bahwa beberapa kelas menyediakan anggota yang sama, antarmuka lebih ringan dan tidak mengunci kelasnya pada satu induk. Kelas yang dirancang dengan antarmuka juga lebih mudah diuji terpisah, karena kontraknya dapat dipenuhi oleh kelas tiruan yang perilakunya disiapkan khusus untuk pengujian.
Sebuah kelas juga dapat menyatakan keduanya sekaligus, yaitu mewarisi kelas induk untuk kode bersamanya sambil mengimplementasikan antarmuka untuk janji kemampuannya. Dengan pembagian itu, keputusan desain tidak lagi berebut satu slot pewarisan, karena peran keduanya sudah terpisah sejak awal. Slot pewarisan tetap satu, sedangkan jumlah antarmuka yang dapat diimplementasikan tidak dibatasi satu.
Kesalahan umum#
Kesalahan pertama adalah melupakan sufiks Implements pada anggota kelas, sehingga compiler menuntut implementasi yang belum dipasangkan seperti pada pesan BC30149. Deklarasi Implements NamaAntarmuka pada kelas saja tidak cukup, karena pengikatan dilakukan per anggota. Perbaikannya adalah menambahkan sufiks pada setiap anggota yang mengisi kontrak.
Kesalahan kedua adalah mencoba membuat objek dari antarmuka dengan New IPenyimpanData(). Compiler menolaknya karena antarmuka tidak memiliki konstruktor dan tidak menyimpan keadaan apa pun, dan variabel bertipe antarmuka wajib diisi dengan objek dari kelas implementasinya. Bentuk yang benar adalah Dim x As IPenyimpanData = New PenyimpanBerkas() atau langsung mendeklarasikannya dengan Dim x As New PenyimpanBerkas().
Kesalahan ketiga adalah memanggil anggota kelas yang tidak termasuk dalam kontrak melalui variabel antarmuka. Variabel penyimpan As IPenyimpanData hanya mengenal Simpan dan Ringkasan, sehingga anggota lain milik PenyimpanBerkas tidak terlihat dari variabel itu meskipun objeknya memiliki anggota tersebut. Apabila anggota kelasnya memang diperlukan, variabelnya bertipe kelas yang bersangkutan, atau kemampuan itu ditambahkan ke dalam kontrak antarmukanya.
Ringkasan#
Interfacemendeklarasikan kontrak berupa kepala anggota tanpa badan, dan kelas mengisi seluruh anggotanya melalui klausaImplementspada kelas serta sufiksImplementsper anggota.- Variabel bertipe antarmuka menampung objek dari kelas implementasi mana pun, sehingga satu perulangan dapat memproses kelas-kelas berbeda secara polimorfis.
- Antarmuka memisahkan kontrak dari implementasinya, boleh diambil lebih dari satu oleh kelas yang sama, dan menjadi jalan keluar larangan pewarisan ganda.
Referensi#
- Interfaces — Microsoft Learn — Ikhtisar antarmuka, deklarasinya, dan implementasinya pada kelas.
- Interface Statement — Microsoft Learn
— Sintaks
Interfacedan aturan anggotanya. - Implements Statement — Microsoft Learn — Klausa pengikatan antarmuka pada deklarasi kelas dan anggotanya.
- Walkthrough: Creating and Implementing Interfaces — Microsoft Learn — Langkah membuat antarmuka dan mengimplementasikannya pada kelas.