it-swarm.asia

Bir sınıfı neden soyut sınıf olarak ilan etmeliyim?

Sözdizimini, 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, ancak diğer sınıf tarafından genişletilebilir

Bunu yapmanın avantajı nedir?

Arayüzden farkı nedir?

Bir sınıfın birden fazla arabirim 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ının farkındayım. Bunu, Java'daki AWT'nin Etkinlik delegasyon modelinden öğrendim.

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

40
Vaibhav Jani

B cevap soyut bir sınıf ve bir arayüz arasındaki farklılıklar açıklamak için iyi bir iş çıkarır, ama neden bir tane beyan etmelisiniz.

Tamamen teknik bir bakış açısından, bir sınıfı soyut olarak ilan etmek için asla gereksinim yoktur.

Aşağıdaki üç sınıfı düşünün:

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

Uygulamasında bariz bir sorun olsa bile, Veritabanı sınıfını soyut yapmak için have yapmıyorsunuz: Bu programı yazarken new Database() ve geçerli olur, ama asla işe yaramaz.

Ne olursa olsun, programınız sadece SqlDatabase ve OracleDatabase örnekleri oluşturduğu sürece, polimorfizm elde edersiniz, şöyle yöntemler yazabilirsiniz:

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

Soyut sınıflar, bir geliştirici öğesinin temel sınıfı başlatmasını engelleyerek durumu geliştirir, çünkü bir geliştiricinin işlevi eksik işlevlere sahip olduğu işaretlenmiştir. 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 minimum işlevi sağladığından emin olursunuz ve saplama yöntemleri koymak konusunda endişelenmenize gerek yoktur ( yukarıdaki gibi) mirasçılar bir şekilde sihirli bir şekilde bilmek = var bir yöntem çalışması için geçersiz kılmak zorunda.

Arayüzler tamamen ayrı bir konudur. Bir arabirim, bir nesne üzerinde hangi işlemlerin gerçekleştirilebileceğini tanımlamanızı sağlar. Genellikle diğer bileşenlerin, nesnelerin hizmetlerini kullanan yöntemler, bileşenler vb. Yazarken arabirimler kullanırsınız, ancak hizmetleri aldığınız gerçek nesne türünün ne olduğu umurumda değildir.

Aşağıdaki yöntemi düşünün:

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

database nesnesinin belirli bir nesneden miras alıp almadığını umursamazsınız, sadece addProduct yöntemine sahip olmasını önemsersiniz. 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ı (bir satır yazmadan önce bağlanmak gibi) paylaşmak için bazı veritabanlarının RemoteDatabase'den nasıl miras aldığına dikkat edin, ancak FileDatabase yalnızca IProductDatabase uygulayan ayrı bir sınıftır.

50
Kevin McCormick

Benzerlikler

Soyutlama için soyut sınıflar ve arayüzler gereklidir. Yeni bir yeni ile örneklenemezler, ancak kontrol kaplarının ters çevrilmesi veya fabrika modelleri ile çözülmesi mümkündür.

Fark

  1. Arayüzler

    • İyi bilinen kamu sözleşmesini, türün yeteneklerini tanımlamak
    • Yatay kalıtımı göstermek için uygulanabilir, yani ilk kalıtım dalında dallanma (örneğin veritabanına, metin dosyasına, XML, SOAP vb.
    • Tüm üyeler herkese açık
    • Uygulamaya izin verilmiyor
    • Miras ç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ıyı, kimliği ve desteklenen bazı varsayılan davranışları tanımlama
    • Dikey kalıtım göstermek için uygulanabilir, yani çeşitli düzeylerde derin dallanma (ör. Etki alanı güdümlü geliştirmede AbstractEntity sınıfı)
    • Üyeler farklı görünürlüklere sahip olabilirler (halktan özelliğe)
    • Bazı üyeleri uygulayabilirsiniz (örneğin * Reader sınıfları)
    • Miras çocuğunun sadece bir temel soyut sınıfı olabilir

Cevabı basit google sorgus ile bulmak gerçekten kolaydır.

16
oleksii

Arayüzden farkı nedir?

Soyut bir sınıfta, bazı yöntemleri uygulayabilir ve gerisini genişletme sınıfı tarafından uygulanmaya bırakabilirsiniz. Bir arabirime yöntem uygulayamazsınız. Sıradan bir sınıfı genişletirken kimseyi hiçbir şeyi geçersiz kılmaya zorlayamazsınız. Soyut bir sınıfla yapabilirsiniz.

11
Joonas Pulakka

Soyut sınıflar "is" içindir ve arayüzler "yapabilir" içindir.

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

8
Tulains Córdova

Derin teknik detayların yanı sıra - soyut sınıflar için bazı yöntemlerin uygulanması gibi, 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.

Soyut (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 gerçek amacını - web kaynaklarına erişmek için tanımlar.

3
Sunny

Wikipedia girişi .

Bir arayüz ile soyut bir sınıf arasındaki temel farklar, soyut bir sınıfın uygulanan yöntemler sağlayabilmesidir. Arabirimlerle yalnızca bildirme yöntemlerini imzalayabilir, imzalarını yazabilirsiniz. Aşağıda, iki arabirimi uygulayan soyut bir sınıfı genişleten bir sınıf örneği verilmiştir: (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 her üç değeri de basan genel bir yöntem sağlar. ImpClass'ta getValue1 ve getValue2'yi MyInterface1 ve MyInterface2 = ve soyut sınıftan 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 okuyabilirsiniz.

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

2
Jalayn
  • Arayüz - birkaç sınıf bir API'yi 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, şu soru ile başlamalısınız: "bu sınıflar mutlaka application mı paylaşıyor, yoksa sadece ortak bir arayüz mı var?"

Yanıt karışık ise, örneğin - bu üç sınıfın uygulamayı paylaşması gerekir, ancak bu diğer ikisi sadece API'larını paylaşır - o zaman bunların beşi için bir arayüz ve ortak olan üçü için soyut bir sınıf yapabilirsiniz kodu.

Uygulamayı paylaşmanın başka yolları da vardır, örneğin bir nesneyi o uygulamayla kapsüllemek için (örneğin Strateji modelinde).

2
Viliam Búr

Geliştiricinin (muhtemelen kendiniz) onu başlatmasına izin verilmesini istemediğinizde bir sınıf özeti beyan edersiniz, çünkü işe yaramaz veya mantıklı olmaz.

Örneğin, farklı türde oyun varlıklarının olduğu bir oyunu düşünün. Hepsi temel GameEntity sınıfından miras alır.

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 abstract olarak ilan edilir, çünkü onu başlatmak mantıklı değildir. Oyun varlıkları ve bazı özellikler için bazı eylemler beyan eder, ancak bu sınıfın hiçbir yerinde bu özellikler başlatılmaz. Bu sınıf, oyun varlıkları için bir şablon görevi görür, ancak kendi başına somutlaştırılması amaçlanmamıştır ve bu şekilde abstract olarak beyan edilmiştir.

Soyut bir sınıf ile 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ışlar kazanmanın bir yoludur.

Örnek olarak oyuna geri dönelim. Enemy sınıfından türetilmiş bir GameEntity sınıfı düşünün. Bu sınıfta attackMeFromDistance(RangedAttacker attacker) yöntemi vardır. Bu yöntem, varlıkların düşmana uzaktan saldırmasına izin vermek içindir.

Gördüğünüz gibi, bu yöntem parametre olarak RangedAttacker türünü alır. Ancak, oyun varlıklarının tümü zaten GameEntity öğesinden devralınır. Başka bir sınıfı genişletemezler.

Örneğin Mage ve Archer sınıflarını ele alalım. Her ikisinin de attackMeFromDistance(RangedAttacker attacker) yönteminde parametre olarak kabul edilmesine izin vermek istiyoruz, ancak bunlar zaten GameEntity öğesinden türetilmiş.

Bunu çözmek için yeni bir arayüz oluşturuyoruz:

interface RangedAttacker{
    public void attackFromDistance();
}

Bu arabirimi uygulayan bir sınıfın attackFromDistance() yöntemini uygulaması gerekir ve böylece saldırganlık yetenekleri arasında değişmesi sağlanır. Bu, attackMeFromDistance yönteminin artık bu arabirimi uygulayan sınıfları güvenli bir şekilde kabul edebileceği anlamına gelir. Yani bu arayüzü Mage ve Archer uygulamak yapmak sorunumuzu çözer.

Bana göre bu arayüzlerin gücü.

Özetlemek gerekirse, bazı sınıflar için bir temel sınıf olmasını istediğinizde genellikle soyut bir sınıf kullanırsınız, ancak tek başına (veya abstract olduğu bir durumda) somutlaştırmak mantıklı olmaz. alt sınıflar tarafından uygulanması gereken yöntemler ve bu durumda derleyici abstract) sınıfını oluşturmanızı sağlar. Tek kalıtım mekanizmasıyla sınırlı kalmadan polimorfik davranış elde etmek için bir arayüz kullanırsınız.

1
Aviv Cohn
  1. Bazı sınıflar (iş mantığı) için ortak olan çok az yöntem vardır. Ve kalan yöntemler farklı. Bu tür senaryolarda, tüm ortak yöntemleri bir sınıfta uygulayabilir ve geri kalanını soyut olarak bildirebilirsiniz. O zaman sınıfı soyut olarak ilan etmelisiniz.
  2. Bazen nesneyi doğrudan sınıfa oluşturmanıza izin vermezsiniz. Bu tür bir sınıfı, sınıfı soyut olarak ilan etmeniz gerekir.
0
Dharani Kumar