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 SqlDatabase
dan OracleDatabase
contoh, 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 database
objek tersebut diwarisi dari objek tertentu, Anda hanya peduli bahwa ia memiliki addProduct
metode. 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
.