Sumber : http://jasonroell.com/2014/12/09/interfaces-vs-abstract-classes-what-should-you-use/
C # adalah bahasa yang luar biasa yang telah matang dan berevolusi selama 14 tahun terakhir. Ini bagus untuk kami para pengembang karena bahasa yang matang memberi kami sejumlah besar fitur bahasa yang dapat kami gunakan.
Namun, dengan banyak kekuatan menjadi banyak tanggung jawab. Beberapa fitur ini dapat disalahgunakan, atau terkadang sulit untuk memahami mengapa Anda memilih untuk menggunakan satu fitur di atas yang lain. Selama bertahun-tahun, fitur yang telah saya lihat banyak pengembang geluti adalah ketika memilih untuk menggunakan antarmuka atau memilih untuk menggunakan kelas abstrak. Keduanya memiliki kelebihan dan kekurangan serta waktu dan tempat yang tepat untuk menggunakannya. Tapi bagaimana cara kita memutuskan ???
Keduanya menyediakan untuk penggunaan kembali fungsionalitas umum antara jenis. Perbedaan yang paling jelas adalah bahwa antarmuka tidak memberikan implementasi untuk fungsi mereka sedangkan kelas abstrak memungkinkan Anda untuk menerapkan beberapa perilaku "dasar" atau "default" dan kemudian memiliki kemampuan untuk "menimpa" perilaku default ini dengan tipe turunan kelas jika perlu .
Ini semua baik dan bagus dan menyediakan untuk penggunaan kembali kode dan mematuhi prinsip pengembangan perangkat lunak KERING (Jangan Ulangi Diri Sendiri). Kelas abstrak sangat bagus untuk digunakan ketika Anda memiliki hubungan “adalah”.
Misalnya: Anjing jenis golden retriever “adalah”. Begitu juga pudel. Mereka berdua bisa menggonggong, seperti semua anjing bisa. Namun, Anda mungkin ingin menyatakan bahwa taman pudel sangat berbeda dari kulit anjing "default". Oleh karena itu, masuk akal bagi Anda untuk mengimplementasikan sesuatu sebagai berikut:
public abstract class Dog
{
public virtual void Bark()
{
Console.WriteLine("Base Class implementation of Bark");
}
}
public class GoldenRetriever : Dog
{
// the Bark method is inherited from the Dog class
}
public class Poodle : Dog
{
// here we are overriding the base functionality of Bark with our new implementation
// specific to the Poodle class
public override void Bark()
{
Console.WriteLine("Poodle's implementation of Bark");
}
}
// Add a list of dogs to a collection and call the bark method.
void Main()
{
var poodle = new Poodle();
var goldenRetriever = new GoldenRetriever();
var dogs = new List<Dog>();
dogs.Add(poodle);
dogs.Add(goldenRetriever);
foreach (var dog in dogs)
{
dog.Bark();
}
}
// Output will be:
// Poodle's implementation of Bark
// Base Class implementation of Bark
//
Seperti yang Anda lihat, ini akan menjadi cara yang bagus untuk menjaga kode Anda KERING dan memungkinkan untuk implementasi kelas dasar dipanggil ketika salah satu jenis hanya dapat mengandalkan Bark default daripada implementasi kasus khusus. Kelas-kelas seperti GoldenRetriever, Boxer, Lab semua bisa mewarisi "default" (kelas bass) Bark tanpa biaya hanya karena mereka menerapkan kelas abstrak Dog.
Tapi saya yakin Anda sudah tahu itu.
Anda di sini karena Anda ingin memahami mengapa Anda mungkin ingin memilih antarmuka daripada kelas abstrak atau sebaliknya. Nah salah satu alasan Anda mungkin ingin memilih antarmuka daripada kelas abstrak adalah ketika Anda tidak memiliki atau ingin mencegah implementasi standar. Ini biasanya karena tipe yang mengimplementasikan antarmuka tidak terkait dalam hubungan "adalah". Sebenarnya, mereka tidak harus berhubungan sama sekali kecuali untuk fakta bahwa setiap jenis "mampu" atau memiliki "kemampuan" untuk melakukan sesuatu atau memiliki sesuatu.
Sekarang apa artinya itu? Misalnya, manusia bukan bebek ... dan bebek bukan manusia. Cukup jelas. Namun, baik bebek dan manusia memiliki "kemampuan" untuk berenang (mengingat bahwa manusia lulus pelajaran berenang di kelas 1 :)). Juga, karena bebek bukan manusia atau sebaliknya, ini bukan hubungan "adalah", tetapi sebaliknya hubungan "mampu" dan kita dapat menggunakan antarmuka untuk menggambarkan bahwa:
// Create ISwimable interface
public interface ISwimable
{
public void Swim();
}
// Have Human implement ISwimable Interface
public class Human : ISwimable
public void Swim()
{
//Human's implementation of Swim
Console.WriteLine("I'm a human swimming!");
}
// Have Duck implement ISwimable interface
public class Duck: ISwimable
{
public void Swim()
{
// Duck's implementation of Swim
Console.WriteLine("Quack! Quack! I'm a Duck swimming!")
}
}
//Now they can both be used in places where you just need an object that has the ability "to swim"
public void ShowHowYouSwim(ISwimable somethingThatCanSwim)
{
somethingThatCanSwim.Swim();
}
public void Main()
{
var human = new Human();
var duck = new Duck();
var listOfThingsThatCanSwim = new List<ISwimable>();
listOfThingsThatCanSwim.Add(duck);
listOfThingsThatCanSwim.Add(human);
foreach (var something in listOfThingsThatCanSwim)
{
ShowHowYouSwim(something);
}
}
// So at runtime the correct implementation of something.Swim() will be called
// Output:
// Quack! Quack! I'm a Duck swimming!
// I'm a human swimming!
Menggunakan antarmuka seperti kode di atas akan memungkinkan Anda untuk mengirimkan objek ke metode yang “mampu” melakukan sesuatu. Kode tidak peduli bagaimana melakukannya ... Yang ia tahu adalah ia bisa memanggil metode Swim pada objek itu dan objek itu akan tahu perilaku mana yang dijalankan pada saat run-time berdasarkan jenisnya.
Sekali lagi, ini membantu kode Anda tetap KERING sehingga Anda tidak perlu menulis beberapa metode yang memanggil objek untuk membentuk sebelumnya fungsi inti yang sama (ShowHowHumanSwims (manusia), ShowHowDuckSwims (bebek), dll.)
Menggunakan antarmuka di sini memungkinkan metode panggilan tidak perlu khawatir tentang jenis apa atau bagaimana perilaku itu diterapkan. Ia hanya tahu bahwa mengingat antarmuka, setiap objek harus menerapkan metode Swim sehingga aman untuk memanggilnya dalam kode sendiri dan memungkinkan perilaku metode Swim ditangani dalam kelasnya sendiri.
Ringkasan:
Jadi aturan utama saya adalah menggunakan kelas abstrak ketika Anda ingin menerapkan fungsionalitas "default" untuk hierarki kelas atau / dan kelas atau tipe yang Anda gunakan untuk berbagi hubungan "is a" (mis. Poodle "adalah "Jenis anjing).
Di sisi lain gunakan antarmuka ketika Anda tidak memiliki hubungan "adalah" tetapi memiliki tipe yang berbagi "kemampuan" untuk melakukan sesuatu atau memiliki sesuatu (mis. Bebek "bukan" manusia. Namun, bebek dan manusia berbagi "Kemampuan" untuk berenang).
Perbedaan lain yang perlu diperhatikan antara kelas abstrak dan antarmuka adalah bahwa kelas dapat mengimplementasikan satu ke banyak antarmuka tetapi kelas hanya bisa mewarisi dari SATU kelas abstrak (atau kelas apa pun dalam hal ini). Ya, Anda dapat membuat kelas sarang dan memiliki hierarki warisan (yang banyak dan harus dimiliki oleh banyak program) tetapi Anda tidak dapat mewarisi dua kelas dalam satu definisi kelas turunan (aturan ini berlaku untuk C #. Dalam beberapa bahasa lain Anda dapat melakukan ini, biasanya hanya karena kurangnya antarmuka dalam bahasa ini).
Ingat juga saat menggunakan antarmuka untuk mematuhi Prinsip Segregasi Antarmuka (ISP). ISP menyatakan bahwa tidak ada klien yang harus dipaksa untuk bergantung pada metode yang tidak digunakannya. Untuk alasan ini antarmuka harus difokuskan pada tugas-tugas tertentu dan biasanya sangat kecil (mis. IDisposable, IComparable).
Kiat lain adalah jika Anda mengembangkan fungsionalitas kecil dan ringkas, gunakan antarmuka. Jika Anda mendesain unit fungsional besar, gunakan kelas abstrak.
Semoga ini jelas bagi sebagian orang!
Juga jika Anda dapat memikirkan contoh yang lebih baik atau ingin menunjukkan sesuatu, silakan lakukan di komentar di bawah!