Kapan harus menggunakan antarmuka, bukan kelas abstrak dan sebaliknya?

427

Ini mungkin pertanyaan OOP umum. Saya ingin melakukan perbandingan generik antara antarmuka dan kelas abstrak berdasarkan penggunaannya.

Kapan seseorang ingin menggunakan antarmuka dan kapan seseorang ingin menggunakan kelas abstrak ?

Chirantan
sumber
1
Ini telah banyak ditanyakan: stackoverflow.com/questions/56867/interface-vs-base-class
mmcdole
1
Sebagai tambahan untuk jawaban di bawah ini adalah daftar pendek yang bagus di mana Anda mungkin ingin memilih antarmuka dan di mana Anda mungkin tidak: Kapan Menggunakan Antarmuka: msdn.microsoft.com/en-us/library/3b5b8ezk(v=vs.80) .aspx
Anthony
gunakan abstrak ketika Anda tidak yakin apa yang akan dilakukan kelas. gunakan antarmuka jika Anda.
Uğur Gümüşhan
Saya tertarik untuk melihat berapa banyak pengembang, yang tidak bekerja di Microsoft, mendefinisikan dan menggunakan antarmuka dalam pengembangan mereka sehari-hari.
user1451111

Jawaban:

432

Saya menulis artikel tentang itu:

Kelas dan antarmuka abstrak

Meringkas:

Ketika kita berbicara tentang kelas abstrak, kita mendefinisikan karakteristik tipe objek; menentukan apa objek itu .

Ketika kita berbicara tentang antarmuka dan mendefinisikan kemampuan yang kita janjikan untuk diberikan, kita berbicara tentang membuat kontrak tentang apa yang bisa dilakukan objek.

Jorge Córdoba
sumber
114
Ini adalah ery membantu: Interfaces do not express something like "a Doberman is a type of dog and every dog can walk" but more like "this thing can walk". Terima kasih
aexl
2
Sepertinya tautan Anda sudah mati.
Kim Ahlstrøm Meyn Mathiassen
Penjelasan Alex di bawah ini, re: perbedaan antara hanya menggambarkan fungsi yang diimplementasikan versus juga menggambarkan keadaan yang disimpan, sepertinya jawaban yang lebih baik untuk pertanyaan ini, karena perbedaannya tidak hanya filosofis.
Duncan Malashock
1
Duncan Malashock, tidak juga. Jawaban Jorge adalah yang lebih baik. Jawaban Alex berfokus pada mekanika, sedangkan Jorge lebih pada semantik.
Nazar Merza
8
Saya suka pernyataan sebelum jawaban yang Anda tentukan:Use abstract classes and inheritance if you can make the statement “A is a B”. Use interfaces if you can make the statement “A is capable of [doing] as”
S1r-Lanzelot
433

Kelas abstrak dapat memiliki status atau fungsi bersama. Antarmuka hanya janji untuk menyediakan status atau fungsi. Kelas abstrak yang baik akan mengurangi jumlah kode yang harus ditulis ulang karena fungsionalitas atau statusnya dapat dibagikan. Antarmuka tidak memiliki informasi yang ditentukan untuk dibagikan

Alex
sumber
65
Bagi saya, ini adalah jawaban terbaik di sini dan ini memalukan karena tidak dipilih lebih tinggi. Ya, ada perbedaan filosofis antara kedua konsep, tetapi titik dasarnya adalah bahwa kelas abstrak memastikan bahwa semua keturunan berbagi fungsionalitas / negara, di mana antarmuka hanya memastikan ikatan yang sama.
drharris
3
Misalnya, kelas dasar abstrak digunakan untuk pola desain metode templat , sedangkan antarmuka digunakan untuk pola desain strategi .
Raedwald
1
Saya pikir ringkasan Jorge menjelaskan yang utama di balik keberadaan keduanya, sedangkan jawaban Alex adalah perbedaan dalam hasil. Saya berharap saya bisa menandai keduanya sebagai jawaban yang benar, tetapi saya masih lebih suka jawaban Jorge.
Chirantan
Dan di sini adalah contoh dengan kode.
shaijut
Bagi saya, ini "Kelas abstrak yang baik akan mengurangi jumlah kode yang harus ditulis ulang karena fungsionalitasnya atau keadaan dapat dibagikan." pernyataan adalah inti dari jawabannya.
Div Tiwari
82

Secara pribadi, saya hampir tidak pernah memiliki kebutuhan untuk menulis kelas abstrak.

Sering kali saya melihat kelas abstrak digunakan (salah), itu karena penulis kelas abstrak menggunakan pola "Templat metode".

Masalah dengan "Templat metode" adalah bahwa itu hampir selalu agak masuk kembali - kelas "turunan" tahu tidak hanya metode "abstrak" dari kelas dasarnya yang diimplementasikan, tetapi juga tentang metode publik dari kelas dasar , meskipun seringkali tidak perlu memanggil mereka.

Contoh (terlalu disederhanakan):

abstract class QuickSorter
{
    public void Sort(object[] items)
    {
        // implementation code that somewhere along the way calls:
        bool less = compare(x,y);
        // ... more implementation code
    }
    abstract bool compare(object lhs, object rhs);
}

Jadi di sini, penulis kelas ini telah menulis algoritma umum dan bermaksud agar orang menggunakannya dengan "mengkhususkan" itu dengan menyediakan "kait" mereka sendiri - dalam hal ini, metode "bandingkan".

Jadi penggunaan yang dimaksud adalah seperti ini:

class NameSorter : QuickSorter
{
    public bool compare(object lhs, object rhs)
    {
        // etc.
    }
}

Masalahnya adalah Anda terlalu banyak menyatukan dua konsep:

  1. Cara membandingkan dua item (item apa yang lebih dulu)
  2. Metode penyortiran item (mis. Quicksort vs merge sort dll.)

Dalam kode di atas, secara teoritis, penulis metode "bandingkan" dapat kembali memanggil metode superclass "Sort" ... meskipun dalam praktiknya mereka tidak akan pernah mau atau perlu melakukan ini.

Harga yang Anda bayar untuk kopling yang tidak dibutuhkan ini adalah sulit untuk mengubah superclass, dan dalam kebanyakan bahasa OO, tidak mungkin untuk mengubahnya saat runtime.

Metode alternatif adalah menggunakan pola desain "Strategi" sebagai gantinya:

interface IComparator
{
    bool compare(object lhs, object rhs);
}

class QuickSorter
{
    private readonly IComparator comparator;
    public QuickSorter(IComparator comparator)
    {
        this.comparator = comparator;
    }

    public void Sort(object[] items)
    {
        // usual code but call comparator.Compare();
    }
}

class NameComparator : IComparator
{
    bool compare(object lhs, object rhs)
    {
        // same code as before;
    }
}

Jadi perhatikan sekarang: Yang kita miliki hanyalah antarmuka, dan implementasi konkret dari antarmuka tersebut. Dalam praktiknya, Anda tidak benar-benar membutuhkan hal lain untuk melakukan desain OO tingkat tinggi.

Untuk "menyembunyikan" fakta bahwa kami telah menerapkan "pengurutan nama" dengan menggunakan kelas "QuickSort" dan "NameComparator", kami mungkin masih menulis metode pabrik di suatu tempat:

ISorter CreateNameSorter()
{
    return new QuickSorter(new NameComparator());
}

Setiap kali Anda memiliki kelas abstrak, Anda dapat melakukan ini ... bahkan ketika ada hubungan re-entran alami antara kelas dasar dan turunan, biasanya membayar untuk membuatnya eksplisit.

Satu pemikiran terakhir: Semua yang kami lakukan di atas adalah "menulis" fungsi "NameSorting" dengan menggunakan fungsi "QuickSort" dan fungsi "NameComparison" ... dalam bahasa pemrograman fungsional, gaya pemrograman ini menjadi lebih alami, dengan kode lebih sedikit.

Paul Hollingsworth
sumber
5
Hanya karena Anda dapat menggunakan kelas Abstrak atau pola Metode Templat tidak berarti Anda harus menghindarinya. Pola Strategi adalah pola yang berbeda untuk situasi yang berbeda seperti dalam contoh ini, tetapi ada banyak contoh di mana pola template jauh lebih cocok daripada Strategi.
Jorge Córdoba
5
Yah, dalam pengalaman saya, saya tidak pernah bertemu mereka (situasi di mana metode template lebih disukai) ... atau jarang pula. Dan itu semua "abstrak" adalah - dukungan bahasa untuk pola desain "metode templat".
Paul Hollingsworth
Ok, saya pernah menggunakannya sekali untuk sistem pakar di mana prosesnya adalah seperti, dapatkan 1. FillTheParameters, 2. Buat Produk Vektor di antara mereka, 3. Untuk Setiap Pasangan menghitung hasil, 4. Gabung hasilnya, di mana langkah 1 dan 3 di mana didelegasikan dan 2 dan 4 dilaksanakan di kelas dasar.
Jorge Córdoba
10
Saya menemukan hampir semua penggunaan kelas abstrak lebih sulit untuk dipahami. Berpikir dari segi kotak yang berkomunikasi satu sama lain daripada hubungan warisan lebih mudah (bagi saya) ... Tapi saya juga setuju bahwa bahasa OO saat ini memaksa terlalu banyak boilerplate ... Fungsional akan menjadi cara untuk membahas OO
Paul Hollingsworth
4
Contoh penyalahgunaan cukup sepele. Ini jarang bermuara pada fungsionalitas seperti dilucuti bagus seperti membandingkan. Jauh lebih umum adalah situasi di mana ada beberapa fungsi default yang diganti atau diperluas oleh kelas turunan (dan dalam kasus yang terakhir ini sangat valid untuk memanggil fungsi kelas dasar). Dalam contoh Anda tidak ada fungsi default, jadi penggunaan kelas abstrak tidak memiliki justifikasi.
SomeWittyUsername
41

Jika Anda melihat java sebagai bahasa OOP,

" antarmuka tidak menyediakan implementasi metode " tidak lagi berlaku dengan peluncuran Java 8. Sekarang java menyediakan implementasi dalam antarmuka untuk metode standar.

Secara sederhana, saya ingin menggunakan

antarmuka: Untuk menerapkan kontrak dengan beberapa objek yang tidak terkait. Ini memberikan kemampuan " HAS A ".

kelas abstrak: Untuk menerapkan perilaku yang sama atau berbeda di antara beberapa objek terkait. Itu membangun hubungan " IS A ".

Situs web Oracle menyediakan perbedaan utama antara interfacedan abstractkelas.

Pertimbangkan menggunakan kelas abstrak jika:

  1. Anda ingin berbagi kode di antara beberapa kelas yang terkait erat.
  2. Anda berharap bahwa kelas yang memperluas kelas abstrak Anda memiliki banyak metode atau bidang umum, atau memerlukan pengubah akses selain publik (seperti yang dilindungi dan pribadi).
  3. Anda ingin mendeklarasikan bidang non-statis atau non-final.

Pertimbangkan menggunakan antarmuka jika:

  1. Anda berharap bahwa kelas yang tidak terkait akan mengimplementasikan antarmuka Anda. Sebagai contoh, banyak objek yang tidak berhubungan dapat mengimplementasikan Serializableantarmuka.
  2. Anda ingin menentukan perilaku tipe data tertentu, tetapi tidak peduli tentang siapa yang mengimplementasikan perilakunya.
  3. Anda ingin memanfaatkan multiple inheritance of type.

Contoh:

Kelas abstrak ( IS A relation)

Pembaca adalah kelas abstrak.

BufferedReader adalah aReader

FileReader adalah aReader

FileReaderdan BufferedReaderdigunakan untuk tujuan bersama: Membaca data, dan mereka dihubungkan melalui Readerkelas.

Antarmuka ( kemampuan HAS A )

Serializable adalah antarmuka.

Asumsikan bahwa Anda memiliki dua kelas dalam aplikasi Anda, yang mengimplementasikan Serializableantarmuka

Employee implements Serializable

Game implements Serializable

Di sini Anda tidak dapat membuat hubungan apa pun melalui Serializableantarmuka antara Employeedan Game, yang dimaksudkan untuk tujuan yang berbeda. Keduanya mampu serialisasi negara dan perbandingan berakhir di sana.

Lihatlah tulisan-tulisan ini:

Bagaimana seharusnya saya menjelaskan perbedaan antara Interface dan kelas Abstrak?

Ravindra babu
sumber
40

OK, saya sendiri baru saja "ngobrol" - ini dia istilah awam (silakan koreksi saya kalau saya salah) - Saya tahu topik ini terlalu keras, tetapi seseorang mungkin akan menemukannya suatu hari nanti ...

Kelas abstrak memungkinkan Anda untuk membuat cetak biru, dan memungkinkan Anda untuk MENGONSTRUKSI (mengimplementasikan) properti dan metode yang Anda ingin SEMUA turunannya miliki.

Antarmuka di sisi lain hanya memungkinkan Anda untuk menyatakan bahwa Anda ingin properti dan / atau metode dengan nama yang diberikan ada di semua kelas yang mengimplementasikannya - tetapi tidak menentukan bagaimana Anda harus mengimplementasikannya. Juga, sebuah kelas dapat mengimplementasikan antarmuka BANYAK, tetapi hanya dapat memperluas kelas SATU Abstrak. Antarmuka lebih merupakan alat arsitektur tingkat tinggi (yang menjadi lebih jelas jika Anda mulai memahami pola desain) - Abstrak memiliki kaki di kedua kubu dan dapat melakukan beberapa pekerjaan kotor juga.

Mengapa menggunakan satu di atas yang lain? Yang pertama memungkinkan untuk definisi yang lebih konkret tentang keturunan - yang terakhir memungkinkan untuk polimorfisme yang lebih besar . Poin terakhir ini penting bagi pengguna akhir / pembuat kode, yang dapat memanfaatkan informasi ini untuk mengimplementasikan AP I (nterface) dalam berbagai kombinasi / bentuk yang sesuai dengan kebutuhan mereka.

Saya pikir ini adalah momen "bohlam" bagi saya - pikirkan antarmuka lebih sedikit dari perspektif penulis dan lebih dari itu dari setiap koder yang datang kemudian dalam rantai yang menambahkan implementasi ke proyek, atau memperluas API.

sunwukung
sumber
untuk membangun ini: Objek yang mengimplementasikan antarmuka mengambil TYPE itu. Ini sangat penting. Jadi, Anda dapat meneruskan variasi antarmuka yang berbeda ke kelas, tetapi merujuknya (dan metode mereka) DENGAN JENIS NAMA INTERFACE. Dengan demikian, Anda menghilangkan kebutuhan untuk beralih atau jika / jika loop. Cobalah tutorial ini pada subjek - ini menunjukkan penggunaan antarmuka melalui Pola Strategi. phpfreaks.com/tutorial/design-patterns---strategy-and-bridge/…
sunwukung
Saya sepenuhnya setuju tentang momen bola lampu Anda: "API (nterface) dalam berbagai kombinasi / bentuk yang sesuai dengan kebutuhan mereka"! Poin yang sangat bagus untuk dibuat.
Trevor Boyd Smith
39

Dua sen saya:

Antarmuka pada dasarnya mendefinisikan kontrak, yang harus dipatuhi oleh setiap kelas pelaksana (mengimplementasikan anggota antarmuka). Itu tidak mengandung kode apa pun.

Di sisi lain, kelas abstrak dapat berisi kode, dan mungkin ada beberapa metode yang ditandai sebagai abstrak yang harus diterapkan oleh kelas pewarisan.

Situasi langka yang saya gunakan kelas abstrak adalah ketika saya memiliki beberapa fungsi default yang mewarisi kelas mungkin tidak menarik dalam mengesampingkan, katakanlah kelas dasar abstrak, yang mewarisi beberapa kelas khusus.

Contoh (yang sangat dasar!): Pertimbangkan kelas dasar yang disebut Nasabah yang memiliki metode abstrak seperti CalculatePayment(), CalculateRewardPoints()dan beberapa metode non-abstrak seperti GetName(), SavePaymentDetails().

Kelas-kelas khusus menyukai RegularCustomer dan GoldCustomerakan mewarisi dari Customerkelas dasar dan mengimplementasikan logika mereka sendiri CalculatePayment()dan CalculateRewardPoints()metode, tetapi menggunakan kembali GetName()dan SavePaymentDetails()metode.

Anda dapat menambahkan lebih banyak fungsi ke kelas abstrak (metode non-abstrak) tanpa memengaruhi kelas anak yang menggunakan versi yang lebih lama. Sedangkan menambahkan metode ke antarmuka akan mempengaruhi semua kelas yang mengimplementasikannya karena mereka sekarang perlu mengimplementasikan anggota antarmuka yang baru ditambahkan.

Kelas abstrak dengan semua anggota abstrak akan mirip dengan antarmuka.

PreethaA
sumber
1
+1 untuk "Anda dapat menambahkan lebih banyak fungsi ke kelas abstrak (yaitu metode non-abstrak) tanpa memengaruhi kelas anak yang menggunakan versi yang lebih lama. Sedangkan menambahkan metode ke antarmuka akan memengaruhi semua kelas yang mengimplementasikannya karena mereka sekarang perlu menerapkan anggota antarmuka yang baru ditambahkan. "
Div Tiwari
antarmuka dapat memiliki metode "default" sehingga tidak memiliki metode impl di antarmuka adalah ide yang salah. "Hubungan Orangtua-ke-Anak" IS-A adalah kuncinya di sini. Juga, "Atribut bersama" vs. "Properti Bersama". misalnya Anjing iS-A Hewan. Tapi seekor anjing juga bisa "Berjalan"
ha9u63ar
30

Kapan melakukan hal yang sangat sederhana jika Anda memiliki konsep yang jelas dalam pikiran Anda.

Kelas abstrak dapat diturunkan sedangkan Antarmuka dapat Diimplementasikan. Ada beberapa perbedaan di antara keduanya. Saat Anda mendapatkan kelas abstrak, hubungan antara kelas turunan dan kelas dasar adalah hubungan 'adalah a'. misalnya, Anjing adalah Hewan, Domba adalah Hewan yang berarti bahwa kelas Berasal mewarisi beberapa properti dari kelas dasar.

Sedangkan untuk implementasi antarmuka, hubungannya "bisa". misalnya, Anjing bisa menjadi anjing mata-mata. Seekor anjing bisa menjadi anjing sirkus. Seekor anjing bisa menjadi anjing ras. Yang berarti Anda menerapkan metode tertentu untuk mendapatkan sesuatu.

Saya harap saya jelas.

Aamir
sumber
11

1.Jika Anda membuat sesuatu yang menyediakan fungsionalitas umum untuk kelas yang tidak terkait, gunakan antarmuka.

2.Jika Anda membuat sesuatu untuk objek yang terkait erat dalam hierarki, gunakan kelas abstrak.

kuttychutty
sumber
7

Saya pikir cara yang paling ringkas untuk mengatakannya adalah sebagai berikut:

Properti bersama => kelas abstrak.
Fungsionalitas bersama => antarmuka.

Dan untuk membuatnya lebih ringkas ...

Contoh Kelas Abstrak:

public abstract class BaseAnimal
{
    public int NumberOfLegs { get; set; }

    protected BaseAnimal(int numberOfLegs)
    {
        NumberOfLegs = numberOfLegs;
    }
}

public class Dog : BaseAnimal
{
    public Dog() : base(4) { }
}

public class Human : BaseAnimal 
{
    public Human() : base(2) { }
}

Karena hewan memiliki properti bersama - jumlah kaki dalam kasus ini - masuk akal untuk membuat kelas abstrak yang berisi properti bersama ini. Ini juga memungkinkan kami untuk menulis kode umum yang beroperasi pada properti itu. Sebagai contoh:

public static int CountAllLegs(List<BaseAnimal> animals)
{
    int legCount = 0;
    foreach (BaseAnimal animal in animals)
    {
        legCount += animal.NumberOfLegs;
    }
    return legCount;
}

Contoh Antarmuka:

public interface IMakeSound
{
    void MakeSound();
}

public class Car : IMakeSound
{
    public void MakeSound() => Console.WriteLine("Vroom!");
}

public class Vuvuzela : IMakeSound
{
    public void MakeSound() => Console.WriteLine("VZZZZZZZZZZZZZ!");        
}

Perhatikan di sini bahwa Vuvuzelas dan Cars adalah hal yang sama sekali berbeda, tetapi mereka memiliki fungsi yang sama: membuat suara. Jadi, sebuah antarmuka masuk akal di sini. Selanjutnya, ini akan memungkinkan pemrogram untuk mengelompokkan hal-hal yang membuat suara bersama di bawah antarmuka umum - IMakeSounddalam hal ini. Dengan desain ini, Anda dapat menulis kode berikut:

List<IMakeSound> soundMakers = new List<ImakeSound>();
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Vuvuzela());

foreach (IMakeSound soundMaker in soundMakers)
{
    soundMaker.MakeSound();
}

Bisakah Anda tahu apa yang akan dihasilkan?

Terakhir, Anda dapat menggabungkan keduanya.

Contoh Gabungan:

public interface IMakeSound
{
    void MakeSound();
}

public abstract class BaseAnimal : IMakeSound
{
    public int NumberOfLegs { get; set; }

    protected BaseAnimal(int numberOfLegs)
    {
        NumberOfLegs = numberOfLegs;
    }

    public abstract void MakeSound();
}

public class Cat : BaseAnimal
{
    public Cat() : base(4) { }

    public override void MakeSound() => Console.WriteLine("Meow!");
}

public class Human : BaseAnimal 
{
    public Human() : base(2) { }

    public override void MakeSound() => Console.WriteLine("Hello, world!");
}

Di sini, kami membutuhkan semua BaseAnimalsuara, tetapi kami belum tahu implementasinya. Dalam kasus seperti itu, kita bisa abstrak implementasi antarmuka dan mendelegasikan implementasinya ke subkelasnya.

Satu poin terakhir, ingat bagaimana dalam contoh kelas abstrak kami dapat beroperasi pada properti bersama dari objek yang berbeda dan dalam contoh antarmuka kami dapat menjalankan fungsi bersama dari objek yang berbeda? Dalam contoh terakhir ini, kita bisa melakukan keduanya.

Domn Werner
sumber
7

Kapan lebih suka kelas abstrak daripada antarmuka?

  1. Jika seseorang berencana untuk memperbarui kelas dasar sepanjang masa program / proyek, yang terbaik adalah membiarkan kelas dasar menjadi kelas abstrak
  2. Jika seseorang mencoba membangun tulang punggung untuk objek yang terkait erat dalam hierarki, sangat bermanfaat untuk menggunakan kelas abstrak

Kapan lebih suka antarmuka daripada kelas abstrak?

  1. Jika seseorang tidak berurusan dengan jenis kerangka kerja hirarkis yang besar, antarmuka akan menjadi pilihan yang bagus
  2. Karena multiple inheritance tidak didukung dengan kelas abstrak (masalah intan), antarmuka dapat menghemat hari
Satya
sumber
Apa yang membuat Anda berpikir bahwa pertanyaan lama yang hampir sepuluh tahun membutuhkan jawaban ke-22?
jonrsharpe
3
Jenis pemikiran yang sama yang membuat saya mencari jawaban sederhana untuk pertanyaan itu.
Satya
1
FWIW, saya sangat suka jawaban ini.
Brent Rittenhouse
6

Kelas mungkin mewarisi dari hanya satu kelas dasar, jadi jika Anda ingin menggunakan kelas abstrak untuk memberikan polimorfisme ke sekelompok kelas, mereka semua harus mewarisi dari kelas itu. Kelas abstrak juga dapat menyediakan anggota yang telah diterapkan. Oleh karena itu, Anda dapat memastikan sejumlah fungsionalitas identik dengan kelas abstrak, tetapi tidak bisa dengan antarmuka.

Berikut adalah beberapa rekomendasi untuk membantu Anda memutuskan apakah akan menggunakan antarmuka atau kelas abstrak untuk memberikan polimorfisme untuk komponen Anda.

  • Jika Anda mengantisipasi membuat beberapa versi komponen Anda, buat kelas abstrak. Kelas abstrak menyediakan cara yang sederhana dan mudah untuk versi komponen Anda. Dengan memperbarui kelas dasar, semua kelas warisan secara otomatis diperbarui dengan perubahan. Antarmuka, di sisi lain, tidak dapat diubah setelah dibuat dengan cara itu. Jika diperlukan versi antarmuka baru, Anda harus membuat antarmuka baru.
  • Jika fungsionalitas yang Anda buat akan berguna di berbagai objek yang berbeda, gunakan antarmuka. Kelas abstrak harus digunakan terutama untuk objek yang terkait erat, sedangkan antarmuka paling cocok untuk menyediakan fungsionalitas umum ke kelas yang tidak terkait.
  • Jika Anda mendesain fungsionalitas yang kecil dan ringkas, gunakan antarmuka. Jika Anda mendesain unit fungsional besar, gunakan kelas abstrak.
  • Jika Anda ingin memberikan fungsionalitas umum yang diimplementasikan di antara semua implementasi komponen Anda, gunakan kelas abstrak. Kelas abstrak memungkinkan Anda untuk mengimplementasikan sebagian kelas Anda, sedangkan antarmuka tidak mengandung implementasi untuk setiap anggota.

Disalin dari:
http://msdn.microsoft.com/en-us/library/scsyfw1d%28v=vs.71%29.aspx

Mazhar
sumber
Tidak ada dalam UML yang menghalangi pewarisan banyak kelas. Warisan berganda ditentukan oleh bahasa pemrograman, bukan oleh UML. Misalnya, pewarisan banyak kelas tidak diizinkan di dalam Java dan C #, karena tetapi diizinkan dalam C ++.
BobRodes
@ KodeBob: Ada sejumlah fitur yang dapat diberikan kerangka kerja berorientasi objek dalam berbagai kombinasi, tetapi tidak di semua kombinasi. Warisan berganda yang digeneralisasi menghindarkan beberapa kombinasi fitur berguna lainnya termasuk kemampuan untuk melemparkan referensi secara langsung ke tipe induk dari instance aktual atau tipe antarmuka apa pun yang didukung dan kemampuan untuk secara independen mengkompilasi tipe dasar dan tipe turunan serta menggabungkannya pada saat run time.
supercat
@supercat Milik Anda adalah penjelasan yang baik tentang beberapa masalah yang dihasilkan dari penggunaan banyak pewarisan. Namun demikian, tidak ada dalam UML yang menghalangi pewarisan multi kelas dalam diagram. Saya menanggapi "Kelas mungkin hanya mewarisi dari satu kelas dasar ..." yang tidak begitu.
BobRodes
@BobRodes: Pertanyaan itu diberi tag Java. Java menyertakan fitur-fitur yang ditunjukkan, dan dengan demikian terbatas pada bentuk-bentuk pewarisan berganda yang tidak dapat menghasilkan "berlian mematikan" (walaupun sebenarnya cara mereka mengimplementasikan implementasi antarmuka default memungkinkan berlian mematikan).
supercat
@supercat Oh, ok. Saya biasanya tidak melihat tag java, jadi pada saat itu saya menulis bahwa saya setidaknya berpikir saya mengomentari jawaban UML. Bagaimanapun, saya setuju dengan komentar Anda.
BobRodes
3

Pertimbangkan menggunakan kelas abstrak jika salah satu dari pernyataan ini berlaku untuk situasi Anda:

  1. Anda ingin berbagi kode di antara beberapa kelas yang terkait erat.
  2. Anda berharap bahwa kelas yang memperluas kelas abstrak Anda memiliki banyak metode atau bidang umum atau memerlukan pengubah akses selain publik (seperti yang dilindungi dan pribadi).
  3. Anda ingin mendeklarasikan bidang non-statis atau non-final. Ini memungkinkan Anda untuk menentukan metode yang dapat mengakses dan mengubah status objek tempat mereka berada.

Pertimbangkan menggunakan antarmuka jika salah satu dari pernyataan ini berlaku untuk situasi Anda:

  1. Anda berharap bahwa kelas yang tidak terkait akan mengimplementasikan antarmuka Anda. Sebagai contoh, interface Comparable dan Cloneable diimplementasikan oleh banyak kelas yang tidak berhubungan.
  2. Anda ingin menentukan perilaku tipe data tertentu, tetapi tidak peduli tentang siapa yang mengimplementasikan perilakunya.
  3. Anda ingin memanfaatkan banyak warisan.

Sumber

Abhijeet Ashok Muneshwar
sumber
2

Jawabannya bervariasi antar bahasa. Sebagai contoh, di Java suatu kelas dapat mengimplementasikan (mewarisi dari) beberapa antarmuka tetapi hanya mewarisi dari satu kelas abstrak. Jadi antarmuka memberi Anda lebih banyak fleksibilitas. Tapi ini tidak benar di C ++.

Nick Fortescue
sumber
2

Bagi saya, saya akan menggunakan antarmuka dalam banyak kasus. Tapi saya lebih suka kelas abstrak dalam beberapa kasus.

Kelas-kelas di OO umumnya mengacu pada implementasi. Saya menggunakan kelas abstrak ketika saya ingin memaksa beberapa detail implementasi untuk anak-anak lain saya pergi dengan antarmuka.

Tentu saja, kelas abstrak berguna tidak hanya dalam memaksa implementasi tetapi juga berbagi beberapa detail spesifik di antara banyak kelas terkait.

La VloZ Merrill
sumber
1

Gunakan kelas abstrak jika Anda ingin memberikan beberapa implementasi dasar.

Sebastian
sumber
1
Terima kasih, Sebastian. Tetapi bagaimana jika saya tidak perlu memiliki implementasi dasar? Wont kelas abstrak dan antarmuka sama maka jika ini adalah satu-satunya perbedaan di antara mereka? Mengapa ada perbedaan?
Chirantan
1
Karena beberapa bahasa tidak memiliki antarmuka - C ++.
jmucchiello
1

di java Anda dapat mewarisi dari satu (abstrak) kelas untuk "menyediakan" fungsionalitas dan Anda dapat mengimplementasikan banyak antarmuka untuk "memastikan" fungsionalitas

Peter Miehle
sumber
lil 'hint: jika Anda ingin mewarisi dari kelas abstrak dan antarmuka, pastikan, bahwa kelas abstrak mengimplementasikan antarmuka
Andreas Niedermair
1

Murni berdasarkan pewarisan, Anda akan menggunakan Abstrak di mana Anda mendefinisikan dengan jelas hubungan abstrak yang abstrak (yaitu hewan -> kucing) dan / atau membutuhkan warisan properti virtual atau non-publik, terutama keadaan bersama (yang tidak bisa didukung oleh Antarmuka ).

Anda harus mencoba dan menyukai komposisi (melalui injeksi ketergantungan) daripada warisan di mana Anda bisa, dan perhatikan bahwa Antarmuka menjadi kontrak mendukung pengujian unit, pemisahan masalah dan (beragam bahasa) pewarisan berganda dengan cara yang tidak bisa dilakukan oleh abstrak.

annakata
sumber
1

Salah satu lokasi yang menarik di mana antarmuka lebih baik daripada kelas abstrak adalah ketika Anda perlu menambahkan fungsionalitas tambahan ke sekelompok objek (terkait atau tidak terkait). Jika Anda tidak bisa memberi mereka kelas abstrak dasar (misalnya, mereka sealedsudah atau sudah memiliki orangtua), Anda bisa memberi mereka antarmuka dummy (kosong), dan kemudian cukup menulis metode ekstensi untuk antarmuka itu.

Dmitri Nesteruk
sumber
0

Ini bisa menjadi panggilan yang sangat sulit untuk ...

Satu pointer yang dapat saya berikan: Objek dapat mengimplementasikan banyak antarmuka, sedangkan objek hanya dapat mewarisi satu kelas dasar (dalam bahasa OO modern seperti c #, saya tahu C ++ memiliki banyak pewarisan - tetapi bukankah itu disukai?)

Mesh
sumber
Multiple inheritence memungkinkan Mixin untuk diimplementasikan tanpa terlihat, Mixin yang ditulis dengan baik mudah digunakan tetapi sangat sulit didapat dan sulit untuk ditulis tanpa gagal di suatu tempat. Mixin cukup keren secara keseluruhan melalui IMO.
Martijn Laarman
Sebenarnya saya tidak, multiple inheritence memang merupakan pencetus debat yang pasti antara kami para geek yang saya lihat sama sekali tidak ada alasan untuk downvote. Sebenarnya saya membatalkan jawaban Anda.
Martijn Laarman
Satu-satunya hal yang saya coba buat adalah bahwa cara-cara untuk Mixin dalam bahasa dengan Single Inheritence juga dimungkinkan (C #, PHP, javascript) tetapi melalui perilaku hacky atau sintaks norak. Saya suka Mixin ketika mereka bekerja tetapi saya masih ragu-ragu tentang apakah dari beberapa pewarisan atau tidak.
Martijn Laarman
Jawaban ini lebih merupakan perbedaan sintaksis daripada perbedaan desain. Saya pikir dia meminta perbedaan desain
Pramod Setlur
0

Kelas abstrak dapat memiliki implementasi.

Antarmuka tidak memiliki implementasi, itu hanya mendefinisikan semacam kontrak.

Mungkin juga ada beberapa perbedaan tergantung bahasa: misalnya C # tidak memiliki banyak pewarisan, tetapi beberapa antarmuka dapat diimplementasikan dalam suatu kelas.

Gerrie Schenck
sumber
Ketika Anda mengatakan, "semacam kontrak", maksud Anda seperti di layanan web?
Chirantan
Secara teknis, layanan web tidak berfungsi dengan antarmuka. Dengan kontrak saya maksudkan pengguna objek tahu metode mana yang ada pada objek itu. Misalnya antarmuka IMouse akan memiliki metode Pindahkan, dan acara tombol mouse kiri dan kanan.
Gerrie Schenck
-1

Aturan jempol dasar adalah: Untuk "Nouns" gunakan kelas Abstrak dan untuk "Verbs" gunakan antarmuka

Misalnya: caradalah kelas abstrak dan drive, kita bisa menjadikannya antarmuka.

GANI
sumber
5
Ini tidak masuk akal, kami juga dapat menempatkan fungsionalitas drivedi dalam mobil - yaitu kelas abstrak.
Arslan Ali