Mengapa saya harus mendeklarasikan kelas sebagai kelas abstrak?

40

Saya tahu sintaksnya, aturan diterapkan ke kelas abstrak dan saya ingin tahu penggunaan kelas abstrak

Kelas abstrak tidak bisa dipakai secara langsung tetapi bisa diperpanjang oleh kelas lain

Apa keuntungan melakukan hal itu?

Apa bedanya dengan Interface?

Saya tahu bahwa satu kelas dapat mengimplementasikan banyak antarmuka tetapi hanya dapat memperluas satu kelas abstrak. Apakah itu hanya perbedaan antara antarmuka dan kelas abstrak?

Saya sadar tentang penggunaan Antarmuka. Saya telah mempelajari hal itu dari model delegasi Acara AWT di Jawa.

Dalam situasi apa saya harus mendeklarasikan kelas sebagai kelas abstrak? Apa manfaatnya?

Vaibhav Jani
sumber
14
Ini sudah ditanyakan, Anda tahu. Pencarian akan menghasilkan pertanyaan lain seperti ini. Anda harus mulai di Google, yang akan membawa Anda ke Stack Overflow. Semua ini adalah duplikat: stackoverflow.com/search?q=abstract+interface .
S.Lott
1
"Penggunaan kelas Abstrak yang baru saja mereka diskusikan ... aturan". Apa? Apa perbedaan antara "aturan" dan "penggunaan"? Ngomong-ngomong, pertanyaan Anda sebenarnya ditanyakan. Aku tahu. Saya jawab itu. Tetap mencari. Penting untuk mempelajari cara menggunakan pencarian.
S.Lott
Maksud saya, "Dalam situasi apa saya harus mendeklarasikan kelas sebagai kelas abstrak? Apa manfaatnya?"
Vaibhav Jani
Antarmuka adalah kelas abstrak murni, itu saja. Mereka satu dalam persamaan. Saya menggunakan kelas abstrak setiap saat untuk fungsi di kelas dasar yang tidak dapat diimplementasikan karena membutuhkan data yang hanya dimiliki oleh subkelas, tetapi saya ingin memastikan bahwa setiap subkelas memiliki fungsi ini dan mengimplementasikannya sesuai dengan itu.
AngryBird
Saya menemukan pola metode templat yang sangat kuat dan kasus penggunaan yang baik untuk kelas abstrak.
m3th0dman

Jawaban:

49

Ini jawabannya melakukan pekerjaan yang baik menjelaskan perbedaan antara kelas abstrak dan antarmuka, tetapi tidak menjawab mengapa Anda harus menyatakan satu.

Dari sudut pandang teknis murni, tidak pernah ada persyaratan untuk menyatakan kelas sebagai abstrak.

Pertimbangkan tiga kelas berikut:

class Database { 
    public String[] getTableNames() { return null; } //or throw an exception? who knows...
}

class SqlDatabase extends Database { } //TODO: override getTableNames

class OracleDatabase extends Database { }  //TODO: override getTableNames

Anda tidak harus membuat kelas database abstrak, meskipun ada masalah yang jelas dengan implementasinya: Ketika Anda menulis program ini, Anda bisa mengetik new Database()dan itu akan valid, tetapi itu tidak akan pernah berhasil.

Apapun, Anda masih akan mendapatkan polimorfisme, sehingga selama program Anda hanya membuat SqlDatabasedan OracleDatabasecontoh, Anda dapat menulis metode seperti:

public void printTableNames(Database database) {
    String[] names = database.getTableNames();
}

Kelas abstrak memperbaiki situasi dengan mencegah pengembang membuat instance kelas dasar, karena pengembang telah menandainya memiliki fungsi yang hilang . Ini juga menyediakan keamanan waktu kompilasi sehingga Anda dapat memastikan bahwa setiap kelas yang memperluas kelas abstrak Anda menyediakan fungsionalitas minimum yang sederhana untuk bekerja, dan Anda tidak perlu khawatir tentang menempatkan metode rintisan (seperti yang di atas) yang dimiliki oleh pewaris. untuk mengetahui secara ajaib bahwa mereka harus mengganti metode untuk membuatnya berfungsi.

Antarmuka adalah topik yang benar-benar terpisah. Antarmuka memungkinkan Anda menggambarkan operasi apa yang dapat dilakukan pada objek. Anda biasanya akan menggunakan antarmuka saat menulis metode, komponen, dll. Yang menggunakan layanan dari komponen lain, objek, tetapi Anda tidak peduli apa jenis objek yang sebenarnya Anda dapatkan dari layanan tersebut.

Pertimbangkan metode berikut:

public void saveToDatabase(IProductDatabase database) {
     database.addProduct(this.getName(), this.getPrice());
}

Anda tidak peduli apakah databaseobjek tersebut diwarisi dari objek tertentu, Anda hanya peduli bahwa ia memiliki addProductmetode. Jadi dalam hal ini, antarmuka lebih cocok daripada membuat semua kelas Anda mewarisi dari kelas dasar yang sama.

Terkadang kombinasi keduanya bekerja dengan sangat baik. Sebagai contoh:

abstract class RemoteDatabase implements IProductDatabase { 
    public abstract String[] connect();
    public abstract void writeRow(string col1, string col2);

    public void addProduct(String name, Double price) {
        connect();
        writeRow(name, price.toString());
    }
}

class SqlDatabase extends RemoteDatabase {
    //TODO override connect and writeRow
}

class OracleDatabase extends RemoteDatabase { 
    //TODO override connect and writeRow
}

class FileDatabase implements IProductDatabase {
    public void addProduct(String name, Double price) {
         //TODO: just write to file
    }
}

Perhatikan bagaimana beberapa database mewarisi dari RemoteDatabase untuk berbagi beberapa fungsi (seperti menghubungkan sebelum menulis baris), tetapi FileDatabase adalah kelas terpisah yang hanya mengimplementasikan IProductDatabase.

Kevin McCormick
sumber
16

Kesamaan

Kelas dan antarmuka abstrak diperlukan untuk abstraksi. Mereka tidak dapat dipakai dengan yang baru , tetapi mungkin untuk diselesaikan dalam inversi wadah kontrol atau melalui pola pabrik.

Perbedaan

  1. Antarmuka

    • Tentukan kontrak publik yang terkenal, kemampuan jenis
    • Berlaku untuk menunjukkan pewarisan horizontal, yaitu bercabang pada warisan tingkat pertama (mis. ILog untuk mendefinisikan fasilitas logging ke basis data, file teks, XML, SOAP dll.)
    • Semua anggota bersifat publik
    • Tidak ada implementasi yang diizinkan
    • Anak warisan dapat memiliki banyak antarmuka untuk diimplementasikan
    • Berguna untuk integrasi pihak ketiga
    • Penamaan biasanya dimulai dengan I
  2. Kelas abstrak

    • Tetapkan struktur, identitas, dan beberapa perilaku yang didukung default
    • Berlaku untuk menunjukkan warisan vertikal, yaitu percabangan dalam pada beberapa level (misalnya kelas AbstractEntity dalam pengembangan yang digerakkan oleh domain)
    • Anggota dapat memiliki visibilitas yang berbeda (dari publik ke pribadi)
    • Anda dapat menerapkan beberapa anggota (mis. * Kelas Pembaca)
    • Anak warisan hanya dapat memiliki satu kelas abstrak dasar

Sebenarnya mudah untuk menemukan jawabannya dengan kueri google sederhana .

oleksii
sumber
apa yang Anda mena dengan implementasi tidak diizinkan? kelas java dapat mengimplementasikan antarmuka.
Sajuuk
@Sajuuk baris itu merujuk ke sebuah antarmuka. Anda tidak dapat memasukkan implementasi kontrak ke dalam antarmuka. Anda mungkin memiliki implementasi standar kontrak di kelas abstrak.
oleksii
11

Apa bedanya dengan Interface?

Di kelas abstrak, Anda bisa mengimplementasikan beberapa metode, dan membiarkan (memaksa) sisanya untuk diimplementasikan oleh kelas yang diperluas. Anda tidak dapat menerapkan metode dalam suatu antarmuka. Anda tidak bisa memaksa siapa pun untuk mengesampingkan apa pun ketika memperluas kelas biasa. Dengan kelas abstrak, Anda bisa.

Joonas Pulakka
sumber
Ini benar-benar membutuhkan pembaruan untuk Java 8, di mana metode standar diperkenalkan.
Haakon Løtveit
8

Kelas abstrak untuk "adalah" hubungan dan antarmuka untuk "bisa melakukan".

Kelas abstrak memungkinkan Anda menambahkan perilaku dasar sehingga programmer tidak perlu membuat kode segalanya, sambil tetap memaksa mereka untuk mengikuti desain Anda.

Tulains Córdova
sumber
3

Selain detail teknis yang mendalam - seperti implementasi beberapa metode untuk kelas abstrak, dll, artinya seperti ini:

Antarmuka mendefinisikan kemampuan umum - IEnumerable mendefinisikan, bahwa kelas yang mengimplementasikan antarmuka ini dapat disebutkan. Itu tidak mengatakan apa-apa tentang kelas itu sendiri.

Abstrak (atau basis) kelas mendefinisikan perilaku - WebRequest mendefinisikan perilaku umum semua kelas anak seperti HttpWebRequest, dll. Ini mendefinisikan makna inti dari kelas dan tujuan sebenarnya - untuk mengakses sumber daya web.

Cerah
sumber
2

Entri Wikipedia .

Perbedaan utama antara antarmuka dan kelas abstrak adalah bahwa kelas abstrak dapat menyediakan metode yang diimplementasikan. Dengan antarmuka, Anda hanya dapat mendeklarasikan metode, tulis tanda tangannya. Berikut ini adalah contoh dari kelas yang memperluas kelas abstrak yang mengimplementasikan dua antarmuka: (java)

interface MyInterface1 {
  string getValue1();
}

interface MyInterface2 {
  string getValue2();
}

abstract class MyAbstractClass implements MyInterface1, MyInterface2{
  void printValues() {
    System.out.println("Value 1: " + getValue1() + ", Value 2: " + getValue2() + 
                       ", Value 3: " + getValue3());
  }

  protected abstract string getValue3();
}

class ImpClass extends MyAbstractClass {
  public string getValue1() {
    return "1";
  }

  public string getValue2() {
    return "2";
  }

  protected string getValue3() {
    return "3";
  }
}

Dalam contoh ini, MyAbstractClass menyediakan metode publik yang mencetak ketiga nilai. Di ImpClass Anda perlu mengimplementasikan getValue1, dan getValue2 masing-masing dari MyInterface1 dan MyInterface2 dan getValue3 dari kelas abstrak.

Voa.

Ada lebih banyak aspek (antarmuka: hanya metode publik, kelas abstrak: metode abstrak yang dilindungi dan abstrak publik) tetapi Anda dapat membacanya sendiri.

Pada catatan terakhir, kelas abstrak yang hanya menyediakan metode abstrak adalah kelas dasar abstrak "murni" alias antarmuka.

Jalayn
sumber
2
  • Antarmuka - ketika beberapa kelas berbagi API (nama metode dan parameter)
  • Kelas abstrak - ketika beberapa kelas berbagi kode yang sama (implementasi)

Dengan kata lain, Anda harus mulai dengan sebuah pertanyaan: "apakah kelas-kelas ini harus berbagi implementasi , atau apakah mereka hanya memiliki antarmuka yang sama ?"

Jika jawabannya beragam, seperti - tiga kelas ini harus berbagi implementasi, tetapi dua lainnya hanya membagikan API mereka - maka Anda dapat membuat antarmuka untuk kelima kelas tersebut, dan kelas abstrak untuk ketiga kelas dengan umum kode.

Ada juga cara lain untuk berbagi implementasi, misalnya untuk merangkum objek dengan implementasi itu (misalnya dalam pola Strategi ).

Viliam Búr
sumber
1

Anda akan mendeklarasikan abstrak kelas ketika Anda tidak ingin pengembang (mungkin diri Anda sendiri) diizinkan untuk membuat instantiate, karena itu tidak akan berfungsi atau tidak masuk akal.

Sebagai contoh, pertimbangkan gim di mana ada berbagai jenis entitas gim. Mereka semua mewarisi dari GameEntitykelas dasar .

abstract class GameEntity{

    int lifePoint, speed, damage;

    public attack(GameEntity target){ target.damage(damage); }

    public damage(int damageInflicted){ lifePoint -= damageInflicted - speed; }

    // etc...

}

Kelas ini dideklarasikan abstractkarena tidak masuk akal untuk membuat instantiate. Ia mendeklarasikan beberapa aksi untuk entitas game dan beberapa atribut, tetapi di kelas ini tidak ada atribut yang diinisialisasi. Kelas ini berfungsi sebagai templat untuk entitas gim, tetapi tidak dimaksudkan untuk dibuat sendiri, dan seperti yang dinyatakan abstract.

Mengenai perbedaan penggunaan antara kelas abstrak dan antarmuka:

Seperti yang saya lihat, antarmuka adalah cara untuk mendapatkan perilaku polimorfik tanpa dibatasi oleh mekanisme pewarisan tunggal beberapa bahasa.

Mari kita kembali ke permainan sebagai contoh. Pertimbangkan kelas Enemyyang berasal dari GameEntity. Kelas ini memiliki metode attackMeFromDistance(RangedAttacker attacker). Metode ini dimaksudkan untuk memungkinkan entitas untuk menyerang musuh dari jauh.

Seperti yang Anda lihat, metode ini menggunakan RangedAttackertipe sebagai parameter. Namun, semua entitas game sudah mewarisi dari GameEntity. Mereka tidak bisa memperpanjang kelas lain.

Ambil kelas Magedan Archermisalnya. Kami ingin memungkinkan keduanya diterima sebagai parameter dalam attackMeFromDistance(RangedAttacker attacker)metode, tetapi mereka sudah diturunkan dari GameEntity.

Untuk mengatasi ini, kami membuat antarmuka baru:

interface RangedAttacker{
    public void attackFromDistance();
}

Kelas yang mengimplementasikan antarmuka ini harus mengimplementasikan attackFromDistance()metode ini, dan dengan demikian dipastikan bahwa ia memiliki berbagai kemampuan menyerang. Ini berarti bahwa attackMeFromDistancemetode sekarang dapat dengan aman menerima kelas yang mengimplementasikan antarmuka ini. Jadi membuat Magedan Archermengimplementasikan antarmuka itu memecahkan masalah kita.

Bagi saya, ini adalah kekuatan antarmuka.

Singkatnya, Anda biasanya akan menggunakan kelas abstrak ketika Anda ingin memiliki kelas dasar untuk beberapa kelas, tetapi tidak masuk akal untuk instantiate dengan sendirinya (atau dalam kasus di mana ia memiliki abstractmetode, yang harus diimplementasikan oleh subclass, dan dalam hal ini kompiler akan memaksa Anda untuk membuat kelas abstract). Anda akan menggunakan antarmuka untuk mendapatkan perilaku polimorfik tanpa dibatasi oleh mekanisme pewarisan tunggal.

Aviv Cohn
sumber
0
  1. Ada kemungkinan terlalu sedikit metode yang umum untuk beberapa kelas (logika bisnis). Dan metode yang tersisa berbeda. Dalam skenario semacam itu Anda dapat menerapkan semua metode umum dalam satu kelas, dan mendeklarasikan sisanya sebagai abstrak. Maka Anda harus mendeklarasikan kelas sebagai abstrak.
  2. Terkadang Anda tidak mengizinkan untuk membuat objek ke kelas secara langsung. Jenis kelas yang Anda butuhkan untuk mendeklarasikan kelas sebagai abstrak.
Dharani Kumar
sumber