Neden bir sınıfı soyut bir sınıf olarak ilan etmeliyim?


40

Sözdizimini biliyorum, soyut sınıfa uygulanan kuralları ve soyut bir sınıfın kullanımını bilmek istiyorum

Soyut sınıf doğrudan başlatılamaz, başka bir sınıf tarafından genişletilebilir.

Bunu yapmanın avantajı nedir?

Arayüzden farkı nedir?

Bir sınıfın birden fazla arayüz uygulayabildiğini ancak yalnızca bir soyut sınıfı genişletebileceğini biliyorum. Bu sadece bir arayüz ile soyut bir sınıf arasındaki fark mı?

Arayüz kullanımı hakkında farkındayım. Bunu Java'daki AWT'nin Event delegasyon modelinden öğrendim.

Hangi durumlarda sınıfı soyut bir sınıf olarak ilan etmeliyim? Bunun faydaları nedir?


14
Bu istendi, biliyorsun. Bir arama bunun gibi diğer soruları ortaya çıkaracaktır. Google’da başlamalısınız, bu sizi Stack Overflow’a yönlendirecektir. Bunların hepsi yineleniyor: stackoverflow.com/search?q=abstract+interface .
S.Lott

1
"Özet dersinin kullanımı sadece tartışıyorlar ... kurallar". Ne? "Kurallar" ile "kullanım" arasındaki fark nedir? Bu arada, kesin sorunuz da soruldu. Biliyorum. Cevapladım. Bakmaya devam et. Aramanın nasıl kullanılacağını öğrenmek önemlidir.
S.Lott

"Hangi durumlarda sınıfı soyut sınıf olarak ilan etmeliyim? Bunun faydası nedir?"
Vaibhav Jani

Arayüz, tamamen soyut bir sınıftır, hepsi bu. Aynı birdir. Temel sınıfı, yalnızca alt sınıfların sahip olduğu verilere ihtiyaç duyduğundan uygulanamayan bir işlev için her zaman soyut sınıfı kullanırım, ancak her alt sınıfın bu işleve sahip olmasını ve buna göre uygulanmasını sağlamak istiyorum.
AngryBird

Şablon yöntem kalıbını çok güçlü ve soyut sınıflar için iyi bir kullanım örneği olarak görüyorum.
m3th0dman

Yanıtlar:


49

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 SqlDatabaseve 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 databaseherhangi bir nesneden nesne devralır, sadece bir olduğunu bakım addProductyö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.


16

benzerlikler

Soyutlama için soyut sınıflar ve arayüzler gereklidir. Yeni bir örnekle başlatılamazlar , ancak kontrol konteynırlarının tersine çevrilmesi veya fabrika modelleriyle çözülmesi mümkündür.

fark

  1. Arayüzler

    • İyi bilinen kamu sözleşmesini, tür kabiliyetlerini tanımlar.
    • Yatay kalıtımı göstermek için uygulanabilir, yani birinci kalıtım seviyesine dallanma (örn. Veritabanına kayıt olanaklarını tanımlamak için ILog, metin dosyası, XML, SOAP vb.)
    • Bütün üyeler herkese açık
    • Uygulamaya izin verilmiyor
    • Kalıtım çocuğu uygulamak için birçok arayüze sahip olabilir
    • Üçüncü taraf entegrasyonu için kullanışlıdır
    • Adlandırma genellikle I ile başlar.
  2. Soyut sınıf

    • Yapı, kimlik ve bazı varsayılan desteklenen davranışları tanımlayın
    • Dikey kalıtım göstermek için uygulanabilir, yani birkaç seviyede derin dallanma (örn. Alan odaklı gelişimde AbstractEntity sınıfı)
    • Üyeler farklı görünürlüklere sahip olabilir (halktan kişiye özel)
    • Bazı üyeleri uygulayabilirsiniz (örn. * Reader sınıfları)
    • Kalıtım çocuğu yalnızca bir temel soyut sınıfa sahip olabilir

Cevabı basit google sorgusu ile bulmak aslında kolaydır .


Uygulamada izin verilenler nelerdir? Java sınıfı arayüzleri uygulayabilir.
Sajuuk

@Sajuuk bu satır bir arayüze atıfta bulunur. Bir sözleşmenin uygulanmasını bir arayüze koyamazsınız. Soyut bir sınıfta bir sözleşmenin varsayılan uygulamasına sahip olabilirsiniz.
oleksii,

11

Arayüzden farkı nedir?

Soyut bir sınıfta, bazı yöntemleri uygulayabilir ve kalan sınıf tarafından uygulanacak olanları bırakabilirsiniz (zorlar). Bir arayüzde yöntemleri uygulayamazsınız. Sıradan bir sınıfı genişletirken kimseyi bir şeyi geçersiz kılmaya zorlayamazsınız. Soyut bir sınıfla yapabilirsiniz.


Bunun için, varsayılan yöntemlerin tanıtıldığı Java 8 için bir güncelleme yapılması gerekiyor.
Haakon Løtveit

8

Soyut sınıflar "bir" dir; ilişkiler ve arayüzler ise "yapabilir" içindir.

Soyut sınıflar temel davranışlar eklemenize izin verir, böylece programcılar her şeyi kodlamak zorunda kalmazlar, ancak yine de tasarımınızı takip etmeye zorlarlar.


3

Derin teknik detayların yanı sıra - soyut sınıflar için bazı metotların uygulanması gibi, yani anlamı şu şekildedir:

Arabirimler ortak yeteneği tanımlar - IEnumerable, bu arabirimi uygulayan sınıfın numaralandırılabileceğini tanımlar. Sınıfın kendisi hakkında hiçbir şey söylemez.

Özet (veya temel) sınıflar davranışı tanımlar - WebRequest, HttpWebRequest, vb. Gibi tüm alt sınıfların ortak davranışını tanımlar. Sınıfın temel anlamını ve asıl amacını tanımlar - web kaynaklarına erişmek.


2

Wikipedia girişi .

Bir arabirim ve soyut bir sınıf arasındaki temel farklar, soyut bir sınıfın uygulanan yöntemler sağlayabileceğidir. Arabirimler ile yalnızca yöntemleri beyan edebilir , imzalarını yazabilirsiniz. İki arayüzü uygulayan soyut bir sınıfı genişleten bir sınıf örneği: (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";
  }
}

Bu örnekte, MyAbstractClass , üç değeri de basan ortak bir yöntem sağlar. In ImpClass aralarından sırasıyla getValue1 ve getValue2 uygulamak gerekir MyInterface1 ve MyInterface2 soyut sınıfından ve getValue3.

Voilà.

Daha fazla yönü var (arayüz: sadece genel yöntemler, soyut sınıf: korumalı soyut ve genel soyut yöntemler) ama bunu kendiniz için okuyabilirsiniz.

Son bir notta, yalnızca soyut yöntemler sağlayan soyut bir sınıf, bir "saf" soyut temel sınıf, yani bir arayüzdür.


2
  • Arabirim - bir kaç sınıf bir API paylaştığında (yöntem adları ve parametreleri)
  • Soyut sınıf - birkaç sınıf aynı kodu paylaştığında (uygulama)

Başka bir deyişle, bir soru ile başlamalısınız: "Bu sınıflar uygulamayı mutlaka paylaşıyor mu , yoksa ortak bir arayüzleri var mı?"

Cevap karışıksa - bu üç sınıfın uygulamayı paylaşması gerekir, ancak bu diğer ikisi yalnızca API'larını paylaşır - o zaman beşinin hepsine bir arabirim ve bu üçüne ortak olan soyut bir sınıf oluşturabilirsiniz. kodu.

Uygulamayı paylaşmanın, örneğin bir nesneyi bu uygulamayla kapsıyor gibi başka yolları da vardır (örneğin, Strateji modelinde).


1

Geliştiricinin (muhtemelen kendinizin) başlatabilmesine izin verilmesini istemediğinizde, işe yaramazsa veya mantıklı olmazsa, sınıf özeti bildirirsiniz.

Örneğin, farklı türde oyun varlıklarının olduğu bir oyun düşünün. Hepsi temel GameEntitysınıftan miras alıyor .

abstract class GameEntity{

    int lifePoint, speed, damage;

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

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

    // etc...

}

Bu sınıf, abstractonu somutlaştırmanın bir anlamı olmayacağı için ilan edildi . Oyun varlıkları ve bazı özellikler için bazı eylemler olduğunu bildirir, ancak bu sınıfın hiçbir yerinde bu özellikler başlatılmaz. Bu sınıf, oyundaki varlıklar için bir şablon görevi görür, ancak kendi başına başlatılması ve ilan edilmesi gerektiği anlamına gelmez abstract.

Soyut bir sınıf ve bir arayüz arasındaki kullanım farkıyla ilgili olarak:

Gördüğüm gibi, bir arayüz bazı dillerin tek miras mekanizmasıyla sınırlı kalmadan polimorfik davranış kazanmanın bir yoludur.

Oyuna örnek olarak dönelim. EnemyTüretilmiş bir sınıf düşünün GameEntity. Bu sınıfın bir yöntemi var attackMeFromDistance(RangedAttacker attacker). Bu yöntem, varlıkların düşmana uzak mesafeden saldırmasına izin vermek içindir.

Gördüğünüz gibi, bu yöntem RangedAttackerparametre olarak bir tür alıyor . Ancak, tüm oyun varlıkları zaten ondan devraldı GameEntity. Başka bir sınıfı uzatamazlar.

Sınıfları al Mageve Archerörneğin. Her ikisinin de attackMeFromDistance(RangedAttacker attacker)yöntemde parametre olarak kabul edilmesine izin vermek istiyoruz , ancak bunlar zaten türetilmiş durumda GameEntity.

Bunu çözmek için yeni bir arayüz yaratıyoruz:

interface RangedAttacker{
    public void attackFromDistance();
}

Bu arayüzü uygulayan bir sınıf attackFromDistance()metodu uygulamalıdır ve bu sayede saldırı yeteneklerinin değişmesi sağlanır. Bu, attackMeFromDistanceyöntemin artık bu arayüzü uygulayan sınıfları güvenle kabul edebileceği anlamına geliyor . Dolayısıyla bu arayüzü oluşturmak Mageve Archeruygulamak bizim sorunumuzu çözüyor.

Bana göre bu, arayüzlerin gücüdür.

Özetlemek gerekirse, bazı sınıflar için temel bir sınıfa sahip olmak istediğinizde genellikle soyut bir sınıf kullanırsınız, ancak bunu kendi başına (veya abstractyöntemlerin olduğu bir durumda olması gereken bir durumda) somutlaştırmak mantıklı olmaz . alt sınıflar tarafından uygulanır ve bu durumda derleyici sizi sınıf yapmanıza zorlar abstract). Tek miras mekanizmasıyla sınırlı olmaksızın polimorfik davranış kazanmak için bir arayüz kullanırsınız.


0
  1. Bazı sınıflar için ortak çok az sayıda yöntem vardır (işletme mantığı). Ve kalan yöntemler farklı. Bu tür senaryolarda, tüm ortak yöntemleri bir sınıfta uygulayabilir ve kalanı soyut olarak ilan edebilirsiniz. O zaman sınıfı soyut olarak ilan etmelisin.
  2. Bazen nesneyi doğrudan sınıfa oluşturmanıza izin vermezsiniz. Sınıfı soyut olarak bildirmeniz gereken bu tür bir sınıf.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.