Bu cevap, soyut bir sınıf ile bir arayüz arasındaki farkları açıklamak için iyi bir iş çıkarsa da , neden bir tanesini açıklamanız gerektiğini yanıtlamaz .
Tamamen teknik açıdan bakıldığında, bir sınıfı soyut olarak ilan etme zorunluluğu yoktur .
Aşağıdaki üç sınıfı göz önünde bulundurun:
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
Sen yok olması bu programı yazarken yazabilirsiniz: bunun uygulanması ile bariz bir sorun olsa bile, Veritabanı sınıfı soyut yapmak new Database()
ve geçerli olacağını, ama bir işe asla.
Ne olursa olsun, yine de polimorfizm elde edersiniz, böylece programınız sadece bunu yapar SqlDatabase
ve OracleDatabase
örnekler verirse, aşağıdaki gibi yöntemler yazabilirsiniz:
public void printTableNames(Database database) {
String[] names = database.getTableNames();
}
Soyut sınıflar, bir geliştiricinin temel sınıfı başlatmasını engelleyerek durumu iyileştirir , çünkü bir geliştirici eksik işlevselliğe sahip olduğunu belirtti . Ayrıca, derleme zamanı güvenliği sağlar, böylece soyut sınıfınızı genişleten herhangi bir sınıfın çalışmak için minimum işlevsellik sağladığından emin olabilirsiniz ve bir şekilde mirasçıların sahip olduğu saplama yöntemlerini (yukarıdaki gibi) koymaktan endişe duymanıza gerek kalmaz sihirli için onlar biliyor olması o iş yapmak için bir yöntem geçersiz kılmak.
Arayüzler tamamen ayrı bir konudur. Arabirim, bir nesnede hangi işlemlerin gerçekleştirilebileceğini açıklamanızı sağlar. Diğer bileşenlerin, nesnelerin hizmetlerini kullanan yöntemler, bileşenler vb.
Aşağıdaki yöntemi göz önünde bulundurun:
public void saveToDatabase(IProductDatabase database) {
database.addProduct(this.getName(), this.getPrice());
}
Sen ister umurumda değil database
herhangi bir nesneden nesne devralır, sadece bir olduğunu bakım addProduct
yöntemi. Dolayısıyla, bu durumda, bir arayüz tüm sınıflarınızın aynı temel sınıftan miras almasını sağlamaktan daha uygundur.
Bazen ikisinin kombinasyonu çok iyi çalışıyor. Örneğin:
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
}
}
Bazı veritabanlarının bazı işlevleri (satır yazmadan önce bağlanmak gibi) paylaşmak için RemoteDatabase'den miras aldıklarına dikkat edin, ancak FileDatabase yalnızca uygulayan ayrı bir sınıftır IProductDatabase
.