Bagaimana saya tahu kapan membuat antarmuka?

196

Saya pada titik dalam pengembangan pembelajaran saya di mana saya merasa harus belajar lebih banyak tentang antarmuka.

Saya sering membaca tentang mereka tetapi sepertinya saya tidak bisa memahami mereka.

Saya telah membaca contoh-contoh seperti: Kelas dasar hewan, dengan antarmuka IAnimal untuk hal-hal seperti 'Berjalan', 'Jalankan', 'GetLegs', dll - tetapi saya belum pernah mengerjakan sesuatu dan merasa seperti "Hei, saya harus menggunakan antarmuka sini!"

Apa yang saya lewatkan? Mengapa ini konsep yang sulit untuk saya pahami! Saya hanya terintimidasi oleh fakta bahwa saya mungkin tidak akan pernah menyadari kebutuhan konkret untuk satu hal - sebagian besar karena beberapa aspek yang hilang dari pemahaman mereka! Itu membuat saya merasa seperti kehilangan sesuatu di atas dalam hal menjadi pengembang! Jika ada yang punya pengalaman seperti ini dan memiliki terobosan saya akan menghargai beberapa tips tentang cara memahami konsep ini. Terima kasih.

pengguna53885
sumber
1
Anda Harus memeriksa stackoverflow.com/q/8531292/1055241
gprathour

Jawaban:

151

itu memecahkan masalah konkret ini:

Anda memiliki a, b, c, d dari 4 jenis. seluruh kode Anda, Anda memiliki sesuatu seperti:

a.Process();
b.Process();
c.Process();
d.Process();

mengapa tidak minta mereka mengimplementasikan IProcessable, dan kemudian lakukan

List<IProcessable> list;

foreach(IProcessable p in list)
    p.Process();

skala ini akan jauh lebih baik ketika Anda menambahkan, katakanlah, 50 jenis kelas yang semuanya melakukan hal yang sama.


Masalah konkret lainnya:

Apakah Anda pernah melihat System.Linq.Enumerable? Ini mendefinisikan satu ton metode ekstensi yang beroperasi pada semua jenis yang mengimplementasikan IEnumerable. Karena apa pun yang mengimplementasikan IEnumerable pada dasarnya mengatakan "Saya mendukung iterasi dalam pola tipe foreach unordered", Anda dapat mendefinisikan perilaku kompleks (Count, Max, Where, Select, dll.) Untuk semua jenis enumerable.

Jimmy
sumber
2
Itu membantu. Apa keuntungan memiliki antarmuka sekarang daripada memiliki semua jenis hanya memiliki implementasi untuk metode Process ()?
user53885
Anda tidak akan dapat menggunakan variabel p yang sama kecuali mereka semua adalah subclass dari tipe dasar yang sama, atau mereka mengimplementasikan antarmuka.
Karl
Anda tidak perlu melakukan casting, dibandingkan dengan 50 kelas yang berbeda dengan metode Proses. C # tidak menggunakan "mengetik bebek", jadi hanya karena A memiliki Proses () dan B memiliki Proses () tidak berarti ada cara umum untuk memanggil keduanya. Anda memerlukan Antarmuka untuk itu.
user7116
Baik. Saya baru saja mengubah "var" menjadi "IProcessable" untuk membuat contoh lebih masuk akal.
Jimmy
2
@Rogerio: Saya mencoba menjadi generik. Intinya bukan bahwa "ketika Anda memiliki hal-hal yang memiliki fungsi Process ()" itu "ketika Anda memiliki hal-hal yang berbagi set metode yang sama". contohnya dapat dengan mudah diubah menjadiforeach(IMyCompanyWidgetFrobber a in list) a.Frob(widget, context);
Jimmy
133

Saya suka jawaban Jimmy, tapi saya merasa perlu menambahkan sesuatu. Kunci untuk semuanya adalah "mampu" dalam IProcess mampu. Ini menunjukkan kemampuan (atau properti, tetapi berarti "kualitas intrinsik", bukan dalam arti properti C #) dari objek yang mengimplementasikan antarmuka. IAnimal mungkin bukan contoh yang baik untuk sebuah antarmuka, tetapi IWalkable mungkin merupakan antarmuka yang baik untuk dimiliki jika sistem Anda memiliki banyak hal yang dapat berjalan. Anda mungkin memiliki kelas yang berasal dari Hewan seperti Anjing, Sapi, Ikan, Ular. Dua yang pertama mungkin akan mengimplementasikan IWalkable, dua yang terakhir tidak berjalan, jadi mereka tidak akan melakukannya. Sekarang Anda bertanya "mengapa tidak hanya memiliki superclass lain, WalkingAnimal, yang berasal dari Anjing dan Sapi?". Jawabannya adalah ketika Anda memiliki sesuatu yang sepenuhnya di luar pohon warisan yang juga dapat berjalan, seperti robot. Robot akan mengimplementasikan IWalkable, tetapi mungkin tidak akan berasal dari Animal. Jika Anda ingin daftar hal-hal yang dapat berjalan,

Sekarang ganti IWalkable dengan sesuatu yang lebih lunak-seperti IPersistable, dan analoginya menjadi lebih dekat dengan apa yang Anda lihat dalam program nyata.

rmeador
sumber
9
Saya suka apa yang Anda temukan - "Ini menunjukkan kemampuan". Antarmuka benar-benar diperlukan ketika Anda harus mendefinisikan kemampuan karena dasar-dasar harus tetap pada kelas "Base" -nya.
Ramiz Uddin
71

Gunakan antarmuka saat implementasi dari fungsi yang sama akan berbeda.

Gunakan kelas abstrak / dasar ketika Anda perlu berbagi implementasi konkret yang umum.

Elemen
sumber
8
Yang pertama disebut polimorfisme. Yang kedua adalah minyak ular - kecuali sublcass adalah baseclass (tidak ada pelanggaran prinsip substitusi Liskov), Anda harus memilih komposisi daripada pewarisan.
Arnis Lapsa
@ArnisLapsa Saya tidak mengerti apa yang Anda maksud dengan "kecuali sublcass adalah baseclass". Kapan sebuah subkelas tidak menjadi "kelas dasar"? (seperti pada iskata kunci)
Marc.2377
32

Pikirkan antarmuka seperti Kontrak. Ini cara untuk mengatakan, "Kelas-kelas ini harus mengikuti seperangkat aturan ini."

Jadi dalam contoh IAnimal, ini adalah cara untuk mengatakan, "Saya HARUS memanggil Run, Walk, dll. Pada kelas yang mengimplementasikan IAnimal."

Mengapa ini berguna? Anda mungkin ingin membangun fungsi yang bergantung pada fakta bahwa Anda harus dapat memanggil Run and Walk, misalnya, pada objek. Anda dapat memiliki yang berikut ini:

public void RunThenWalk(Monkey m) {
    m.Run();
    m.Walk();
}

public void RunThenWalk(Dog d) {
    d.Run();
    d.Walk();
}

... dan ulangi untuk semua objek yang Anda tahu dapat berlari dan berjalan. Namun, dengan antarmuka IAnimal Anda, Anda dapat menentukan fungsi satu kali sebagai berikut:

public void RunThenWalk(IAnimal a) {
    a.Run();
    a.Walk();
}

Dengan memprogram melawan antarmuka, Anda pada dasarnya mempercayai kelas untuk mengimplementasikan maksud antarmuka. Jadi dalam contoh kita, pemikirannya adalah "Saya tidak peduli bagaimana mereka Berlari dan Berjalan, selama mereka Berlari dan Berjalan. RunThenWalk saya akan valid selama mereka memenuhi perjanjian itu. Ini berfungsi dengan sangat baik tanpa mengetahui hal lain tentang kelas."

Ada juga diskusi yang bagus dalam pertanyaan terkait ini .

Larsenal
sumber
1
Jangan lupa tentang independensi implementasi. Antarmuka memungkinkan seseorang untuk tidak peduli bagaimana fungsi yang mendasarinya diimplementasikan, hanya saja ia melakukan apa yang dikatakan Antarmuka.
Matthew Brubaker
18

Jangan terlalu khawatir. Banyak pengembang, jarang perlu menulis antarmuka. Anda akan sering menggunakan antarmuka yang tersedia dalam kerangka .NET , tetapi jika Anda tidak merasa perlu untuk menulisnya dalam waktu dekat tidak ada yang mengejutkan tentang itu.

Contoh yang selalu saya berikan kepada seseorang adalah jika Anda memiliki kelas Perahu Layar dan kelas Viper. Mereka mewarisi kelas Perahu dan kelas Mobil masing-masing. Sekarang katakan bahwa Anda perlu mengulang semua objek ini dan memanggil Drive()metode mereka . Meskipun Anda dapat menulis beberapa kode seperti berikut:

if(myObject is Boat)
    ((Boat)myObject).Drive()
else
    if (myObject is Car)
        ((Car)myObject).Drive()

Akan jauh lebih mudah untuk menulis:

((IDrivable)myObject).Drive()
Spencer Ruport
sumber
16

Jimmy benar, ketika Anda ingin dapat menggunakan variabel tunggal untuk beberapa jenis, tetapi semua jenis itu menerapkan metode yang sama melalui deklarasi antarmuka. Kemudian Anda dapat memanggil mereka metode utama pada variabel yang diketik antarmuka.

Namun, ada alasan kedua untuk menggunakan antarmuka. Ketika arsitek proyek adalah orang yang berbeda dari coder implementasi, atau ada beberapa coders implementasi dan satu manajer proyek. Orang yang bertanggung jawab dapat menulis sejumlah besar antarmuka dan melihat bahwa sistem saling beroperasi, dan kemudian menyerahkannya kepada pengembang untuk mengisi antarmuka dengan kelas implementasi. Ini adalah cara terbaik untuk memastikan banyak orang menulis kelas yang kompatibel, dan mereka dapat melakukannya secara paralel.

Karl
sumber
15

Saya suka analogi tentara.

Sersan tidak peduli jika Anda seorang pengembang perangkat lunak , musisi atau pengacara .
Anda diperlakukan sebagai prajurit .

uml

Lebih mudah bagi sersan untuk tidak repot dengan detail spesifik orang yang bekerja
bersamanya , memperlakukan semua orang sebagai abstraksi tentara (... dan menghukum mereka ketika mereka gagal bertindak seperti orang lain).

Kemampuan orang untuk bertindak seperti tentara disebut polimorfisme.

Antarmuka adalah konstruksi perangkat lunak yang membantu mencapai polimorfisme.

Perlu detail abstrak untuk mencapai kesederhanaan adalah jawaban untuk pertanyaan Anda.

Polimorfisme , yang secara etimologis berarti "banyak bentuk," adalah kemampuan untuk memperlakukan objek dari setiap subkelas dari kelas dasar seolah-olah itu adalah objek dari kelas dasar. Kelas dasar memiliki, oleh karena itu, banyak bentuk: kelas dasar itu sendiri, dan salah satu dari subkelasnya.

(..) Ini membuat kode Anda lebih mudah untuk Anda tulis dan lebih mudah dipahami orang lain. Itu juga membuat kode Anda bisa diperluas, karena subclass lain dapat ditambahkan kemudian ke keluarga jenis, dan objek dari subclass baru itu juga akan bekerja dengan kode yang ada.

Arnis Lapsa
sumber
14

Dalam pengalaman saya, kekuatan pendorong untuk membuat antarmuka tidak terjadi sampai saya mulai melakukan pengujian unit dengan kerangka kerja mengejek. Menjadi sangat jelas bahwa menggunakan antarmuka akan membuat mengejek lebih mudah (karena kerangka kerja bergantung pada metode yang virtual). Setelah saya mulai, saya melihat nilai abstrak antarmuka untuk kelas saya dari implementasi. Bahkan jika saya tidak membuat antarmuka yang sebenarnya, saya mencoba sekarang untuk membuat metode saya virtual (menyediakan antarmuka implisit yang dapat diganti).

Ada banyak alasan lain yang saya temukan untuk memperkuat praktik baik refactoring ke antarmuka, tetapi unit testing / mengejek adalah apa yang memberikan "momen aha" awal dari pengalaman praktis.

EDIT : Untuk memperjelas, dengan unit testing dan ejekan saya selalu memiliki dua implementasi - implementasi nyata, konkret dan implementasi ejekan alternatif yang digunakan dalam pengujian. Setelah Anda memiliki dua implementasi, nilai antarmuka menjadi jelas - berurusan dengannya dalam hal antarmuka sehingga Anda dapat mengganti implementasi kapan saja. Dalam hal ini saya menggantinya dengan antarmuka tiruan. Saya tahu bahwa saya bisa melakukan ini tanpa antarmuka yang sebenarnya jika kelas saya dibangun dengan benar, tetapi menggunakan antarmuka yang sebenarnya memperkuat ini dan membuatnya lebih bersih (lebih jelas bagi pembaca). Tanpa dorongan ini, saya tidak berpikir saya akan menghargai nilai antarmuka karena sebagian besar kelas saya saja, pernah memiliki implementasi konkret tunggal.

tvanfosson
sumber
Hal yang benar untuk alasan yang salah. Dalam kasus Anda - Anda berakhir dengan apa yang disebut "antarmuka header" dan menambahkan kompleksitas kelebihan bobot mencapai kesederhanaan.
Arnis Lapsa
@Arnis - pengujian unit adalah "alasan yang salah", mudah mengejek kelas untuk menghapus dependensi dalam pengujian adalah "alasan yang salah". Maaf, tapi saya tidak setuju.
tvanfosson
1
tes harus memengaruhi desain secara tidak langsung dengan memberikan umpan balik jika kode diuji atau tidak. menambahkan poin ekstensibilitas untuk meningkatkan testabilitas itu sendiri seperti curang. Saya pikir Mark Seeman meringkasnya dengan baik bit.ly/esi8Wp
Arnis Lapsa
1
@Arnis - jadi apakah Anda menggunakan tiruan sama sekali dalam pengujian unit Anda? Jika tidak, bagaimana Anda menghapus ketergantungan pada dependensi. Apakah Anda menggunakan DI sama sekali? Pengujian unit mendorong saya untuk menggunakan ejekan dan DI; mengejek dan DI membuktikan nilai praktik yang baik dalam menggunakan antarmuka untuk mendefinisikan kontrak sedemikian rupa sehingga tidak ada pemahaman akademis yang pernah bisa. Karena saya mengadopsi TDD, kode saya jauh lebih sedikit daripada yang seharusnya. Saya pikir itu hal yang baik.
tvanfosson
hanya mengatakan bahwa dekomposisi yang tidak sesuai dengan yang disebut persendian alami mengarah pada kohesi yang rendah dan kompleksitas yang tidak perlu.
Arnis Lapsa
10

Beberapa contoh non-pemrograman yang mungkin membantu Anda melihat penggunaan antarmuka yang tepat dalam pemrograman.

Ada antarmuka antara perangkat listrik dan jaringan listrik - ini adalah seperangkat konvensi tentang bentuk colokan dan soket dan voltase / arus yang melintasinya. Jika Anda ingin menerapkan perangkat listrik baru, selama steker Anda mengikuti aturan itu akan bisa mendapatkan layanan dari jaringan. Hal ini membuat ekstensibilitas menjadi sangat mudah dan menghilangkan atau menurunkan biaya koordinasi : Anda tidak perlu memberi tahu penyedia listrik tentang cara kerja perangkat baru Anda dan mencapai kesepakatan terpisah tentang cara menghubungkan perangkat baru Anda ke jaringan.

Negara-negara memiliki pengukur rel standar. Hal ini memungkinkan pembagian kerja antara perusahaan rekayasa yang meletakkan rel dan perusahaan rekayasa yang membangun kereta untuk berjalan di atas rel itu, dan memungkinkan perusahaan kereta api untuk mengganti dan meningkatkan kereta tanpa menata ulang seluruh sistem.

Layanan yang disajikan bisnis kepada klien dapat digambarkan sebagai antarmuka: antarmuka yang terdefinisi dengan baik menekankan layanan dan menyembunyikan cara . Ketika Anda memasukkan surat ke dalam kotak surat, Anda mengharapkan sistem pengiriman surat dalam waktu tertentu tetapi Anda tidak memiliki harapan tentang bagaimana surat itu dikirim: Anda tidak perlu tahu , dan layanan pos memiliki fleksibilitas untuk pilih cara pengiriman yang paling memenuhi persyaratan dan keadaan saat ini. Pengecualian untuk ini adalah kemampuan pelanggan untuk memilih pos udara - itu bukan jenis antarmuka yang akan dirancang oleh programmer komputer modern, karena itu mengungkapkan terlalu banyak implementasi.

Contoh dari alam: Saya tidak terlalu suka makan (), makesSound (), bergerak (), dll contoh. Mereka menggambarkan perilaku, yang benar, tetapi mereka tidak menggambarkan interaksi dan bagaimana mereka diaktifkan . Contoh nyata dari antarmuka yang memungkinkan interaksi di alam berkaitan dengan reproduksi, misalnya bunga menyediakan antarmuka tertentu untuk lebah sehingga penyerbukan dapat terjadi.


sumber
5

Sangat mungkin untuk menjalani seluruh hidup Anda sebagai pengembang .net dan tidak pernah menulis antarmuka Anda sendiri. Bagaimanapun, kami selamat tanpa mereka selama beberapa dekade dan bahasa kami masih lengkap Turing.

Saya tidak bisa memberi tahu Anda mengapa Anda membutuhkan antarmuka, tetapi saya dapat memberi Anda daftar tempat kami menggunakannya dalam proyek kami saat ini:

  1. Dalam model plug-in kami, kami memuat plug-in dengan antarmuka dan menyediakan antarmuka itu untuk disesuaikan dengan penulis plug-in.

  2. Dalam sistem pengiriman pesan antar-mesin, semua kelas pesan mengimplementasikan antarmuka spesifik dan "tidak dibuka" menggunakan antarmuka.

  3. Sistem manajemen konfigurasi kami mendefinisikan antarmuka yang digunakan untuk mengatur dan mengambil pengaturan konfigurasi.

  4. Kami memiliki satu antarmuka yang kami gunakan untuk menghindari masalah referensi lingkaran yang tidak menyenangkan. (Jangan lakukan ini jika Anda tidak perlu.)

Saya kira jika ada aturan, itu menggunakan antarmuka ketika Anda ingin mengelompokkan beberapa kelas dalam hubungan is-a, tetapi Anda tidak ingin memberikan implementasi apa pun di kelas dasar.

Ya - Jake itu.
sumber
5

Contoh kode (kombinasi Andrew's dengan ekstra saya di apa-tujuan-dari-antarmuka ), yang juga membuat alasan mengapa antarmuka bukannya kelas abstrak pada bahasa tanpa dukungan untuk banyak pewarisan (c # dan Jawa):

interface ILogger
{
    void Log();
}
class FileLogger : ILogger
{
    public void Log() { }
}
class DataBaseLogger : ILogger
{
    public void Log() { }
}
public class MySpecialLogger : SpecialLoggerBase, ILogger
{
    public void Log() { }
}

Perhatikan bahwa FileLogger dan DataBaseLogger tidak memerlukan antarmuka (bisa berupa kelas dasar abstrak Logger). Tetapi pertimbangkan Anda diharuskan untuk menggunakan logger pihak ketiga yang memaksa Anda untuk menggunakan kelas dasar (katakan saja itu memperlihatkan metode yang dilindungi yang Anda Harus gunakan). Karena bahasa tidak mendukung pewarisan berganda, Anda tidak akan dapat menggunakan pendekatan kelas dasar abstrak.

Intinya adalah: gunakan antarmuka bila mungkin untuk mendapatkan fleksibilitas ekstra pada kode Anda. Implementasi Anda kurang terikat, sehingga mengakomodasi perubahan yang lebih baik.

eglasius
sumber
4

Saya telah menggunakan antarmuka sekarang dan kemudian dan inilah penggunaan terakhir saya (nama telah digeneralisasi):

Saya memiliki banyak kontrol khusus pada WinForm yang perlu menyimpan data ke objek bisnis saya. Salah satu pendekatan adalah memanggil setiap kontrol secara terpisah:

myBusinessObject.Save(controlA.Data);
myBusinessObject.Save(controlB.Data);
myBusinessObject.Save(controlC.Data);

Masalah dengan implementasi ini adalah bahwa setiap kali saya menambahkan kontrol, saya harus masuk ke metode "Simpan Data" dan menambahkan kontrol baru.

Saya mengubah kontrol saya untuk mengimplementasikan antarmuka ISaveable yang memiliki metode SaveToBusinessObject (...) jadi sekarang metode "Simpan Data" saya beralih melalui kontrol dan jika menemukan satu yang ISaveable, ia memanggil SaveToBusinessObject. Jadi sekarang ketika kontrol baru diperlukan, yang harus dilakukan seseorang adalah mengimplementasikan ISaveable pada objek itu (dan tidak pernah menyentuh kelas lain).

foreach(Control c in Controls)
{
  ISaveable s = c as ISaveable;

  if( s != null )
      s.SaveToBusinessObject(myBusinessObject);
}

Seringkali manfaat yang tidak terealisasi untuk antarmuka adalah bahwa Anda melokalisasi modifikasi. Setelah ditentukan, Anda jarang akan mengubah keseluruhan alur aplikasi tetapi Anda akan sering melakukan perubahan pada level detail. Saat Anda menyimpan detail di objek tertentu, perubahan di ProcessA tidak akan memengaruhi perubahan di ProcessB. (Kelas dasar juga memberi Anda manfaat ini.)

EDIT: Manfaat lain adalah kekhususan dalam tindakan. Seperti dalam contoh saya, semua yang ingin saya lakukan adalah menyimpan data; Saya tidak peduli apa jenis kontrolnya atau apakah bisa melakukan hal lain - Saya hanya ingin tahu apakah saya bisa menyimpan data dalam kontrol. Itu membuat kode simpan saya cukup jelas - tidak ada pemeriksaan untuk melihat apakah itu teks, angka, boolean atau apa pun karena kontrol kustom menangani semua itu.

Austin Salonen
sumber
4

Anda harus mendefinisikan antarmuka begitu Anda harus memaksakan perilaku untuk kelas Anda.

Perilaku Hewan mungkin melibatkan Berjalan, Makan, Berlari, dll. Oleh karena itu, Anda mendefinisikannya sebagai antarmuka.

Contoh praktis lain adalah antarmuka ActionListener (atau Runnable). Anda akan menerapkannya ketika Anda perlu melacak acara tertentu. Oleh karena itu, Anda perlu menyediakan implementasi untuk actionPerformed(Event e)metode di kelas Anda (atau subkelas). Demikian pula, untuk antarmuka Runnable, Anda menyediakan implementasi untuk public void run()metode ini.

Juga, Anda dapat memiliki antarmuka ini diimplementasikan oleh sejumlah kelas.

Contoh lain di mana Antarmuka digunakan (di Jawa) adalah untuk mengimplementasikan multiple inheritance yang ditawarkan dalam C ++.

Tulisan di batu nisan
sumber
3
Tolong Tuhan buat mereka berhenti mengatakan hal-hal seperti multiple inheritance sehubungan dengan interface. Anda TIDAK mewarisi antarmuka di kelas. Anda MELAKSANAKANnya .
Andrei Rînea
4

Asumsikan Anda ingin membuat model gangguan yang mungkin terjadi ketika Anda mencoba untuk tidur.

Model sebelum antarmuka

masukkan deskripsi gambar di sini

class Mosquito {
    void flyAroundYourHead(){}
}

class Neighbour{
    void startScreaming(){}
}

class LampJustOutsideYourWindow(){
    void shineJustThroughYourWindow() {}
}

Seperti yang Anda lihat dengan jelas banyak 'hal' dapat mengganggu ketika Anda mencoba untuk tidur.

Penggunaan kelas tanpa antarmuka

Tetapi ketika menggunakan kelas-kelas ini kita memiliki masalah. Mereka tidak memiliki kesamaan. Anda harus memanggil setiap metode secara terpisah.

class TestAnnoyingThings{
    void testAnnoyingThinks(Mosquito mosquito, Neighbour neighbour, LampJustOutsideYourWindow lamp){
         if(mosquito != null){
             mosquito.flyAroundYourHead();
         }
         if(neighbour!= null){
             neighbour.startScreaming();
         }
         if(lamp!= null){
             lamp.shineJustThroughYourWindow();
         }
    }
}

Model dengan antarmuka

Untuk mengatasi masalah ini kita bisa memperkenalkan iterfacemasukkan deskripsi gambar di sini

interface Annoying{
   public void annoy();

}

Dan mengimplementasikannya di dalam kelas

class Mosquito implements Annoying {
    void flyAroundYourHead(){}

    void annoy(){
        flyAroundYourHead();
    }
}

class Neighbour implements Annoying{
    void startScreaming(){}

    void annoy(){
        startScreaming();
    }
}

class LampJustOutsideYourWindow implements Annoying{
    void shineJustThroughYourWindow() {}

    void annoy(){
        shineJustThroughYourWindow();
    }
}

Penggunaan dengan antarmuka

Yang akan membuat penggunaan kelas-kelas ini lebih mudah

class TestAnnoyingThings{
    void testAnnoyingThinks(Annoying annoying){
        annoying.annoy();
    }
}
Marcin Szymczak
sumber
Ok, tapi bukankah Neighbourdan LampJustOutsideYourWindowjuga harus mengimplementasikan Annoying?
Stardust
Ya, terima kasih telah menunjukkannya. Saya telah mengedit dengan perubahan ini
Marcin Szymczak
2

Contoh termudah untuk diberikan adalah sesuatu seperti Pemroses Pembayaran. (Paypal, PDS, dll.).

Misalnya Anda membuat antarmuka IPaymentProcessor yang memiliki metode ProcessACH dan ProcessCreditCard.

Anda sekarang dapat menerapkan implementasi Paypal yang konkret. Membuat metode-metode itu memanggil fungsi spesifik PayPal.

Jika nanti Anda memutuskan untuk beralih ke penyedia lain, Anda bisa. Cukup buat implementasi konkret lain untuk penyedia baru. Karena Anda terikat pada antarmuka (kontrak), Anda dapat menukar yang mana aplikasi Anda gunakan tanpa mengubah kode yang mengkonsumsinya.

Tusukan
sumber
2

Ini juga memungkinkan Anda untuk melakukan pengujian unit Mock (.Net). Jika kelas Anda menggunakan antarmuka, Anda dapat mengejek objek dalam pengujian unit Anda dan dengan mudah menguji logika (tanpa benar-benar mengenai database, atau layanan web, dll).

http://www.nmock.org/

Jobo
sumber
2

Jika Anda menelusuri kumpulan .NET Framework dan menelusuri ke kelas dasar untuk objek standar apa pun, Anda akan melihat banyak antarmuka (anggota dinamai ISomeName).

Antarmuka pada dasarnya untuk menerapkan kerangka kerja, besar atau kecil. Saya merasakan hal yang sama tentang antarmuka sampai saya ingin menulis kerangka kerja saya sendiri. Saya juga menemukan bahwa pemahaman antarmuka membantu saya mempelajari kerangka kerja lebih cepat. Saat Anda ingin menulis solusi yang lebih elegan untuk apa saja, Anda akan menemukan bahwa antarmuka sangat masuk akal. Ini seperti metode membiarkan kelas mengenakan pakaian yang sesuai untuk pekerjaan itu. Lebih penting lagi, antarmuka memungkinkan sistem menjadi lebih banyak mendokumentasikan diri sendiri, karena objek yang kompleks menjadi kurang kompleks ketika kelas mengimplementasikan antarmuka, yang membantu mengkategorikan fungsinya.

Kelas mengimplementasikan antarmuka ketika mereka ingin dapat berpartisipasi dalam suatu kerangka kerja secara eksplisit atau implisit. Misalnya, IDisposable adalah antarmuka umum yang menyediakan tanda tangan metode untuk metode Buang () populer dan berguna. Dalam suatu kerangka kerja, semua yang Anda atau pengembang lain perlu ketahui tentang kelas adalah bahwa jika mengimplementasikan IDisposable, maka Anda tahu bahwa ((IDisposable) myObject) .Dispose () tersedia untuk dipanggil untuk tujuan pembersihan.

CONTOH CLASSIC: tanpa mengimplementasikan antarmuka IDisposable, Anda tidak dapat menggunakan konstruksi kata kunci "using ()" dalam C #, karena mengharuskan objek apa pun yang ditentukan sebagai parameter dapat secara implisit dilemparkan ke IDisposable.

CONTOH KOMPLEKS: Contoh yang lebih kompleks adalah kelas System.ComponentModel.Component. Kelas ini mengimplementasikan IDisposable dan IComponent. Sebagian besar, jika tidak semua, .NET objek yang memiliki desainer visual yang terkait dengannya menerapkan IComponent sehingga IDE akan dapat berinteraksi dengan komponen.

KESIMPULAN: Ketika Anda menjadi lebih akrab dengan .NET Framework, hal pertama yang akan Anda lakukan ketika menemukan kelas baru di Object Browser atau dalam alat .NET Reflector (gratis) ( http://www.red-gate.com / produk / reflektor / ) adalah untuk memeriksa untuk melihat dari kelas mana ia mewarisi dan juga antarmuka yang diimplementasikan. .NET Reflector bahkan lebih baik daripada Object Browser karena memungkinkan Anda melihat kelas yang diturunkan juga. Itu memungkinkan Anda untuk belajar tentang semua objek yang berasal dari kelas tertentu, sehingga berpotensi mempelajari tentang fungsionalitas kerangka kerja yang Anda tidak tahu ada. Ini sangat penting ketika diperbarui atau ruang nama baru ditambahkan ke .NET Framework.

EnocNRoll - AnandaGopal Pardue
sumber
2

Pertimbangkan Anda membuat game menembak orang pertama. Pemain memiliki beberapa senjata untuk dipilih.

Kita dapat memiliki antarmuka Gunyang mendefinisikan suatu fungsi shoot().

Kita membutuhkan subclass Gunkelas yang berbeda yaitu ShotGun Sniperdan sebagainya.

ShotGun implements Gun{
    public void shoot(){
       \\shotgun implementation of shoot.
    } 
}

Sniper implements Gun{
    public void shoot(){
       \\sniper implementation of shoot.
    } 
}

Kelas Penembak

Penembak memiliki semua senjata di Armor-nya. Mari kita buat Listuntuk mewakilinya.

List<Gun> listOfGuns = new ArrayList<Gun>();

Penembak memutar senjatanya, saat diperlukan, menggunakan fungsi switchGun()

public void switchGun(){
    //code to cycle through the guns from the list of guns.
    currentGun = //the next gun in the list.
}

Kita dapat mengatur Gun saat ini, menggunakan fungsi di atas dan hanya memanggil shoot()fungsi, ketika fire()dipanggil.

public void fire(){
    currentGun.shoot();
}

Perilaku fungsi pemotretan akan bervariasi sesuai dengan implementasi Gunantarmuka yang berbeda.

Kesimpulan

Buat antarmuka, ketika fungsi kelas tergantung pada fungsi dari kelas lain , yang dapat berubah perilakunya, berdasarkan instance (objek) dari kelas yang diimplementasikan.

untuk mis fire()fungsi dari Shooterkelas mengharapkan senjata ( Sniper, ShotGun) untuk mengimplementasikan shoot()fungsi. Jadi jika kita mengganti pistol dan menembak.

shooter.switchGun();
shooter.fire();

Kami telah mengubah perilaku fire()fungsi.

Tukang sortir
sumber
1

Untuk memperluas apa yang dikatakan Larsenal. Antarmuka adalah kontrak yang harus diikuti oleh semua kelas pelaksana. Karena itu, Anda dapat menggunakan teknik yang disebut pemrograman untuk kontrak. Ini memungkinkan perangkat lunak Anda untuk menjadi implementasi independen.

Matthew Brubaker
sumber
1

Antarmuka umumnya digunakan ketika Anda ingin mendefinisikan perilaku yang dapat ditunjukkan oleh objek.

Contoh yang baik dari hal ini di dunia .NET adalah antarmuka IDisposable , yang digunakan pada kelas Microsoft yang menggunakan sumber daya sistem yang harus dirilis secara manual. Ini mensyaratkan bahwa kelas yang mengimplementasikannya memiliki metode Buang ().

(Metode Buang () juga dipanggil oleh konstruk bahasa menggunakan untuk VB.NET dan C # , yang hanya berfungsi pada IDisposables)

Ingatlah bahwa Anda dapat memeriksa apakah suatu objek mengimplementasikan antarmuka tertentu dengan menggunakan konstruksi seperti TypeOf ... Is(VB.NET), is(C #), instanceof(Java), dll ...

Powerlord
sumber
1

Karena beberapa orang mungkin sudah menjawab, antarmuka dapat digunakan untuk menegakkan perilaku tertentu antar kelas yang tidak akan menerapkan perilaku tersebut dengan cara yang sama. Jadi dengan mengimplementasikan antarmuka, Anda mengatakan bahwa kelas Anda memiliki perilaku antarmuka. Antarmuka IAnimal tidak akan menjadi antarmuka yang khas karena kelas Anjing, Kucing, Burung, dll. Adalah jenis hewan, dan mungkin harus diperluas, yang merupakan kasus warisan. Sebagai gantinya, sebuah antarmuka akan lebih seperti perilaku hewan dalam kasus ini, seperti IRunnable, IFlyable, ITrainable, dll.

Antarmuka baik untuk banyak hal, salah satu kuncinya adalah pluggability. Misalnya, mendeklarasikan metode yang memiliki parameter Daftar akan memungkinkan apa pun yang mengimplementasikan antarmuka Daftar untuk diteruskan, memungkinkan pengembang untuk menghapus dan menyambungkan daftar yang berbeda di lain waktu tanpa harus menulis ulang satu ton kode.

Mungkin Anda tidak akan pernah menggunakan antarmuka, tetapi jika Anda merancang proyek dari awal, terutama semacam kerangka kerja, Anda mungkin ingin membiasakan diri dengannya.

Saya akan merekomendasikan membaca bab tentang antarmuka dalam Desain Java oleh Coad, Mayfield, dan Kern. Mereka menjelaskannya sedikit lebih baik daripada teks pengantar rata-rata. Jika Anda tidak menggunakan Java, Anda bisa membaca awal bab ini, yang sebagian besar hanya konsep.

Ryan Thames
sumber
1

Seperti halnya teknik pemrograman yang menambah fleksibilitas ke sistem Anda, antarmuka juga menambah tingkat kerumitan. Mereka sering kali hebat dan Anda bisa menggunakannya di mana saja (Anda dapat membuat antarmuka untuk semua kelas Anda) - tetapi dengan melakukannya, Anda akan menciptakan sistem yang lebih kompleks yang akan lebih sulit untuk dipelihara.

Ada trade-off di sini, seperti biasa: fleksibilitas atas rawatan. Mana yang lebih penting? Tidak ada jawaban - itu tergantung pada proyek. Tapi ingatlah bahwa setiap perangkat lunak harus dipelihara ...

Jadi saran saya: jangan gunakan antarmuka sampai Anda benar-benar membutuhkannya. (Dengan Visual Studio, Anda dapat mengekstrak antarmuka dari kelas yang ada dalam 2 detik - jadi jangan terburu-buru.)

Karena itu, kapan Anda perlu membuat antarmuka?

Saya melakukannya ketika saya refactoring metode yang tiba - tiba perlu memproses dua atau lebih kelas yang serupa. Saya kemudian membuat sebuah antarmuka, menetapkan antarmuka ini ke dua (atau lebih) kelas yang sama dan saya mengubah tipe parameter metode (ganti tipe kelas dengan tipe antarmuka).

Dan itu bekerja: o)

Satu pengecualian: ketika saya ketika mengejek objek, antarmuka jauh lebih mudah digunakan. Jadi saya sering membuat antarmuka hanya untuk ini.

PS: ketika saya menulis "antarmuka", maksud saya: "antarmuka kelas dasar", termasuk kelas antarmuka murni. Perhatikan bahwa kelas abstrak sering kali merupakan taruhan yang lebih baik daripada antarmuka murni karena Anda dapat menambahkan logika pada mereka.

Salam, Sylvain.

Sylvain Rodrigue
sumber
1

Antarmuka akan menjadi jelas ketika Anda menjadi pengembang perpustakaan (seseorang yang kode untuk coders lain). Sebagian besar dari kita mulai sebagai pengembang aplikasi , tempat kami menggunakan API dan pustaka pemrograman yang ada.

Sepanjang garis yang sama bahwa Antarmuka adalah kontrak , belum ada yang menyebutkan bahwa Antarmuka adalah cara yang bagus untuk membuat beberapa bagian dari kode Anda stabil . Itu sangat berguna ketika itu adalah proyek tim (atau ketika Anda sedang mengembangkan kode yang digunakan oleh pengembang lain). Jadi, inilah skenario konkret untuk Anda:

Saat Anda mengembangkan kode dalam tim , orang lain mungkin akan menggunakan kode yang Anda tulis. Mereka akan sangat senang ketika mereka membuat kode untuk antarmuka (stabil) Anda, dan Anda akan senang ketika Anda memiliki kebebasan untuk mengubah implementasi Anda (tersembunyi di belakang antarmuka) tanpa melanggar kode tim Anda. Ini adalah varian dari menyembunyikan informasi (antarmuka bersifat publik, implementasi disembunyikan dari pemrogram klien). Baca lebih lanjut tentang variasi yang dilindungi .

Lihat juga pertanyaan terkait ini tentang pengkodean ke Antarmuka .

Fuhrmanator
sumber
1

Ada begitu banyak tujuan untuk menggunakan antarmuka.

  1. Gunakan dalam perilaku polimorfik. Di mana Anda ingin memanggil metode khusus kelas anak dengan inteface yang memiliki referensi ke kelas anak.

  2. Memiliki kontrak dengan kelas untuk mengimplementasikan semua metode yang diperlukan, seperti penggunaan paling umum adalah dengan objek COM, di mana kelas wrapper dihasilkan pada DLL yang mewarisi antarmuka; metode ini dipanggil di belakang layar, dan Anda hanya perlu mengimplementasikannya tetapi dengan struktur yang sama seperti yang didefinisikan dalam COM DLL yang hanya dapat Anda ketahui melalui antarmuka yang mereka tampilkan.

  3. Untuk mengurangi penggunaan memori dengan memuat metode khusus di kelas. Seperti jika Anda memiliki tiga objek bisnis dan mereka diimplementasikan dalam satu kelas, Anda dapat menggunakan tiga antarmuka.

Misalnya IUser, IOrder, IOrderItem

public interface IUser()
{

void AddUser(string name ,string fname);

}

// Same for IOrder and IOrderItem
//


public class  BusinessLayer: IUser, IOrder, IOrderItem

{    
    public void AddUser(string name ,string fname)
    {
        // Do stuffs here.
    }

    // All methods from all interfaces must be implemented.

}

Jika Anda hanya ingin menambahkan pengguna, lakukan seperti ini:

IUser user = new (IUser)BusinessLayer();

// It will load  all methods into memory which are declared in the IUser interface.

user.AddUser();
Marc.2377
sumber