Soyut bir sınıf yerine bir arayüz ne zaman kullanılır?


427

Bu genel bir OOP sorusu olabilir. Kullanımları temelinde bir arayüz ile soyut bir sınıf arasında genel bir karşılaştırma yapmak istedim.

Ne zaman bir arayüz ve ne zaman soyut bir sınıf kullanmak istersiniz ?



1
Aşağıdaki cevaplara ek olarak, arayüzleri tercih etmek isteyebileceğiniz ve nerede istemeyeceğinizin güzel kısa bir listesi: Arayüz Ne Zaman Kullanılır: msdn.microsoft.com/en-us/library/3b5b8ezk(v=vs.80) .aspx
Anthony

sınıfın ne yapacağından emin olmadığınız zaman soyut kullanın. Eğer arayüz kullanıyorsanız.
Uğur Gümüşhan

Microsoft'ta çalışmayan kaç geliştiricinin günlük geliştirmelerinde arabirimleri tanımlayıp kullandığını görmek istiyorum.
user1451111

Yanıtlar:


431

Bununla ilgili bir makale yazdım:

Soyut sınıflar ve arayüzler

Özetleme:

Soyut sınıflar hakkında konuştuğumuzda, bir nesne tipinin özelliklerini tanımlarız; bir nesnenin ne olduğunu belirleme .

Bir arayüz hakkında konuştuğumuzda ve sunmayı vaat ettiğimiz yetenekleri tanımladığımızda , nesnenin neler yapabileceği hakkında bir sözleşme oluşturmaktan bahsediyoruz .


114
Bu ery yardımcı oldu: Interfaces do not express something like "a Doberman is a type of dog and every dog can walk" but more like "this thing can walk". Teşekkür ederim
aexl

2
Bağlantınız öldü.
Kim Ahlstrøm Meyn Mathiassen

Alex'in aşağıdaki açıklaması, yeniden: sadece uygulanan fonksiyonları tanımlamakla aynı zamanda depolanan durumu tanımlamak arasındaki fark, bu soruya daha iyi bir cevap gibi görünüyor, çünkü farklılıklar sadece felsefi değil.
Duncan Malashock

1
Duncan Malashock, pek değil. Jorge'nin cevabı daha iyi. Alex'in cevabı mekaniğe odaklanırken, Jorge daha çok anlambilime odaklanır.
Nazar Merza

8
Belirttiğiniz yanıttan önceki ifadeyi Use abstract classes and inheritance if you can make the statement “A is a B”. Use interfaces if you can make the statement “A is capable of [doing] as”
beğeniyorum

433

Soyut bir sınıfın durumu veya işlevselliği paylaşılan olabilir. Bir arabirim yalnızca durumu veya işlevselliği sağlama vaadidir. İyi bir soyut sınıf, işlevselliği veya durumu paylaşılabildiği için yeniden yazılması gereken kod miktarını azaltacaktır. Arabirimin paylaşılacak tanımlanmış bir bilgisi yok


65
Bu benim için buradaki en iyi cevap ve daha yüksek oy kullanılmamış olması bir utanç. Evet, iki kavram arasında felsefi farklılıklar vardır, ancak kök nokta, soyut sınıfların, tüm torunların bir arabirimin yalnızca ortak bir bağ sağladığını işlevselliği / durumu paylaşmasını sağlamasıdır.
drharris

3
Örneğin, şablon yöntemi tasarım deseni için soyut bir temel sınıf kullanılırken, strateji tasarım deseni için bir arayüz kullanılır .
Raedwald

1
Sanırım Jorge'nin özeti her ikisi için de varlığın arkasında yatan ilkeyi açıklarken, Alex'in cevabı sonuçlardaki farktır. Keşke ikisini de doğru cevap olarak işaretleyebilseydim, ama yine de Jorge'nin cevabını tercih ederim.
Chirantan

Ve İşte bir örnek kod ile.
shaijut

Bana göre bu "İyi bir soyut sınıf, işlevselliği veya durumu paylaşılabildiği için yeniden yazılması gereken kod miktarını azaltacaktır." ifadesi cevabın özüdür.
Div Tiwari

82

Şahsen, neredeyse hiç soyut ders yazma ihtiyacım olmadı.

Çoğu zaman soyut sınıfların (mis) kullanıldığını görüyorum, çünkü soyut sınıfın yazarı "Şablon yöntemi" desenini kullanıyor.

"Şablon yöntemi" ile ilgili sorun, neredeyse her zaman biraz yeniden girilmesidir - "türetilmiş" sınıf, temel sınıfının uyguladığı "soyut" yöntemi değil, aynı zamanda temel sınıfın genel yöntemlerini de bilir. , çoğu zaman onları aramak zorunda olmasa da.

(Aşırı basitleştirilmiş) örneği:

abstract class QuickSorter
{
    public void Sort(object[] items)
    {
        // implementation code that somewhere along the way calls:
        bool less = compare(x,y);
        // ... more implementation code
    }
    abstract bool compare(object lhs, object rhs);
}

Yani burada, bu sınıfın yazarı genel bir algoritma yazmıştır ve insanların kendi "kancalarını" sağlayarak "uzmanlaştırarak" - bu durumda bir "karşılaştırma" yöntemi kullanmasını amaçlamaktadır.

Yani amaçlanan kullanım şöyle:

class NameSorter : QuickSorter
{
    public bool compare(object lhs, object rhs)
    {
        // etc.
    }
}

Buradaki sorun, iki kavramı gereğince birleştirmiş olmanızdır:

  1. İki öğeyi karşılaştırmanın bir yolu (önce hangi öğenin gitmesi gerekir)
  2. Öğeleri sıralama yöntemi (yani hızlı sıralama vs birleştirme sıralaması vb.)

Yukarıdaki kodda, teorik olarak, "karşılaştır" yönteminin yazarı, pratikte bunu asla istemeyecek veya yapmayacak olsa bile , yeniden üst sınıf "Sırala" yöntemine geri çağırabilir.

Bu gereksiz kuplaj için ödediğiniz fiyat, üst sınıfı değiştirmenin zor olması ve çoğu OO dilinde, çalışma zamanında değiştirmek imkansız olmasıdır.

Alternatif yöntem bunun yerine "Strateji" tasarım modelini kullanmaktır:

interface IComparator
{
    bool compare(object lhs, object rhs);
}

class QuickSorter
{
    private readonly IComparator comparator;
    public QuickSorter(IComparator comparator)
    {
        this.comparator = comparator;
    }

    public void Sort(object[] items)
    {
        // usual code but call comparator.Compare();
    }
}

class NameComparator : IComparator
{
    bool compare(object lhs, object rhs)
    {
        // same code as before;
    }
}

Şimdi dikkat edin: Sahip olduğumuz tek şey arayüzler ve bu arayüzlerin somut uygulamaları. Uygulamada, üst düzey bir OO tasarımı yapmak için başka bir şeye ihtiyacınız yoktur.

Bir "QuickSort" sınıfı ve bir "NameComparator" kullanarak "adların sıralanmasını" uyguladığımız gerçeğini "gizlemek" için, yine de bir yere bir fabrika yöntemi yazabiliriz:

ISorter CreateNameSorter()
{
    return new QuickSorter(new NameComparator());
}

Herhangi tabanı ve türetilmiş sınıfın arasında doğal yeniden giriş ilişki olduğunu bile bunu yapabilirsiniz soyut sınıf var zaman ..., genellikle onları açık hale getirmek için öder.

Son bir düşünce: Yukarıda yaptığımız tek şey, bir "QuickSort" işlevi ve bir "NameComparison" işlevi kullanarak bir "NameSorting" işlevi "oluşturmak" dır ... işlevsel bir programlama dilinde, bu programlama tarzı daha doğal hale gelir, daha az kodla.


5
Soyut sınıfları veya Şablon Yöntemi desenini kullanabilmeniz, bunlardan kaçınmanız gerektiği anlamına gelmez. Strateji Kalıbı, bu örnekteki gibi farklı bir durum için farklı bir kalıptır, ancak bir şablon kalıbının Stratejiden daha uygun olduğu birçok örnek vardır.
Jorge Córdoba

5
Benim deneyimlerime göre, asla bunlarla karşılaşmam (şablon yönteminin tercih edildiği durumlar) ... ya da nadiren. Ve hepsi "soyut" - "şablon yöntemi" tasarım deseni için dil desteği.
Paul Hollingsworth

Tamam, bir kez sürecin gibi bir şey olduğu bir uzman sistem için kullandım, 1 olsun. FillTheParameters, 2. Vektör Ürünü aralarında yapın. burada delege edilen ve 2 ve 4 temel sınıfta uygulanmaktadır.
Jorge Córdoba

10
Soyut sınıfların neredeyse her türlü kullanımını daha zor buluyorum. Miras ilişkileri yerine birbirleriyle iletişim kuran kutular açısından düşünmek daha kolay (benim için) ... Ama aynı zamanda mevcut OO dillerinin çok fazla ortak plakayı zorladığını kabul ediyorum ... Fonksiyonel OO üzerinden geçmenin yolu olacak
Paul Hollingsworth

4
Yanlış kullanım örneği oldukça önemsizdir. Karşılaştırma gibi güzel soyulmuş işlevsellik nadiren kaynar. Çok daha yaygın olarak türetilmiş sınıfların değiştirdiği veya genişlettiği bazı varsayılan işlevselliklerin olduğu durumlar vardır (ve ikinci durumda temel sınıf işlevini çağırmak için tamamen geçerlidir). Örneğinizde varsayılan bir işlevsellik yoktur, bu nedenle soyut sınıf kullanımının bir gerekçesi yoktur.
SomeWittyUsername

41

Java'ya OOP dili olarak bakıyorsanız,

" arabirim yöntem uygulaması sağlamaz " artık Java 8 lansmanı ile geçerli değildir. Java, varsayılan yöntemler için arayüzde uygulama sağlar.

Basit bir ifadeyle, kullanmak istiyorum

interface: İlişkisiz birden çok nesne tarafından bir sözleşme uygulamak. " HAS A " yeteneği sağlar.

soyut sınıf: Aynı veya farklı davranışı birden çok ilişkili nesne arasında uygulamak. " IS A " ilişkisinikurar.

Oracle web sitesiinterface ve abstractsınıf arasındaki önemli farkları sağlar .

Aşağıdaki durumlarda soyut sınıfları kullanmayı düşünün :

  1. Kodu yakından ilişkili birkaç sınıf arasında paylaşmak istiyorsunuz.
  2. Soyut sınıfınızı genişleten sınıfların birçok ortak yöntemi veya alanı olmasını veya genel (erişim korumalı ve özel gibi) dışında erişim değiştiricileri gerektirmesini beklersiniz.
  3. Statik olmayan veya nihai olmayan alanları bildirmek istiyorsunuz.

Aşağıdaki durumlarda arayüzleri kullanmayı düşünün :

  1. İlişkisiz sınıfların arayüzünüzü uygulamasını beklersiniz. Örneğin, ilgisiz birçok nesne Serializablearabirim uygulayabilir .
  2. Belirli bir veri türünün davranışını belirtmek istiyorsunuz, ancak davranışını kimin uyguladığından endişe etmiyorsunuz.
  3. Birden fazla tür mirasından yararlanmak istiyorsunuz.

Misal:

Soyut sınıf ( IS A ilişkisi)

Okuyucu soyut bir sınıftır.

BufferedReader birReader

FileReader birReader

FileReaderve BufferedReaderortak amaç için kullanılır: Verileri okumak ve bunlar Readersınıf yoluyla ilişkilidir .

Arayüz ( HAS A yeteneği)

Serileştirilebilir bir arabirimdir.

Uygulamanızda Serializablearayüz uygulayan iki sınıfınız olduğunu varsayın

Employee implements Serializable

Game implements Serializable

Burada , farklı amaçlar için olan ve Serializablearasındaki arayüz aracılığıyla herhangi bir ilişki kuramazsınız. Her ikisi de devleti seri hale getirme yeteneğine sahiptir ve karşılaştırma burada biter.EmployeeGame

Şu yayınlara bir göz atın:

Bir Interface ve Abstract sınıfı arasındaki farkı nasıl açıklamalıydım?


40

Tamam, sadece kendimi "grokked" olması - burada layman açısından (eğer yanılıyorsam beni düzeltmekten çekinmeyin) - Bu konunun oooooold olduğunu biliyorum, ama bir gün başka biri rastlamak olabilir ...

Soyut sınıflar, bir plan oluşturmanıza ve TÜM torunlarının sahip olmasını istediğiniz özellikleri ve yöntemleri ayrıca İNŞAAT (uygulamanızı) sağlar.

Öte yandan bir arabirim, yalnızca belirli bir ada sahip özelliklerin ve / veya yöntemlerin onu uygulayan tüm sınıflarda olmasını istediğinizi bildirmenize izin verir - ancak bunu nasıl uygulamanız gerektiğini belirtmez. Ayrıca, bir sınıf MANY arabirimlerini uygulayabilir, ancak yalnızca ONE Abstract sınıfını genişletebilir. Bir Arabirim daha üst düzey bir mimari araçtır (tasarım desenlerini kavramaya başlarsanız daha net olur) - Bir Özet'in her iki kampta da bir ayağı vardır ve kirli işlerin bir kısmını da yapabilir.

Neden birini diğerinin üzerinde kullanıyorsunuz? Birincisi torunların daha somut bir tanımına izin verir - ikincisi daha fazla polimorfizme izin verir . Bu son nokta, AP I'yi (arayüz) ihtiyaçlarına uygun çeşitli kombinasyonlarda / şekillerde uygulamak için bu bilgiyi kullanabilen son kullanıcı / kodlayıcı için önemlidir .

Bu benim için "ampul" anıydı - yazarın bakış açısından daha az ve daha sonra bir projeye uygulama ekleyen veya bir API genişleten zincirde daha sonra gelen herhangi bir kodlayıcının arayüzlerini düşünün .


bunun üzerine inşa etmek için: Bir arabirimi uygulayan bir nesne TYPE'yi alır. Bu çok önemli. Böylece, arabirimin farklı varyasyonlarını bir sınıfa aktarabilirsiniz, ancak bunlara (ve yöntemlerine) ARABİRİMİN TÜR ADI İLE başvurabilirsiniz. Böylece, bir anahtar veya if / else döngüsüne olan ihtiyacı ortadan kaldırmış olursunuz. Konuyla ilgili bu öğreticiyi deneyin - Strateji Deseni aracılığıyla bir arayüzün kullanımını gösterir. phpfreaks.com/tutorial/design-patterns---strategy-and-bridge/…
sunwukung

Ampul anınızı tamamen kabul ediyorum: "İhtiyaçlarına uygun çeşitli kombinasyonlarda / şekillerde API (nterface)"! Bunu yapmak için çok iyi bir nokta.
Trevor Boyd Smith

39

Benim görüşüm:

Bir arayüz temel olarak, herhangi bir uygulayıcı sınıfın uyması gereken bir arayüz tanımlar (arayüz üyelerini uygulamak). Herhangi bir kod içermiyor.

Öte yandan, soyut bir sınıf kod içerebilir ve miras olarak atanan bir sınıfın uygulaması gereken soyut olarak işaretlenmiş bazı yöntemler olabilir.

Soyut sınıfları kullandığım nadir durumlar, miras sınıfının, bazı temel sınıfların miras aldığı geçersiz bir temel sınıfın geçersiz kılmasında ilginç olmayabileceği bazı varsayılan işlevlere sahip olduğumdur.

Örnek (çok ilkel bir!): Gibi soyut yöntemleri vardır bir temel sınıf olarak adlandırılan Müşteriyi düşünün CalculatePayment(), CalculateRewardPoints()ve benzeri olmayan bazı soyut yöntemler GetName(), SavePaymentDetails().

Gibi sınıflar uzmanlaşmış RegularCustomer ve GoldCustomergelen devralır Customertemel sınıf ve kendi uygulamak CalculatePayment()ve CalculateRewardPoints()yöntem mantığı, ancak yeniden kullanmak GetName()ve SavePaymentDetails()yöntemleri.

Daha eski bir sürümü kullanan alt sınıfları etkilemeden soyut bir sınıfa (soyut olmayan yöntemler) daha fazla işlevsellik ekleyebilirsiniz. Bir arabirime yöntem eklemek, yeni eklenen arabirim üyelerini uygulamak zorunda oldukları için onu uygulayan tüm sınıfları etkileyecektir.

Tüm soyut üyeleri içeren soyut bir sınıf bir arayüze benzer.


1
+1 for "Eski bir sürümü kullanan alt sınıfları etkilemeden soyut bir sınıfa daha fazla işlevsellik ekleyebilirsiniz (soyut olmayan yöntemler). yeni eklenen arayüz üyeleri. "
Div Tiwari

arabirimler "varsayılan" yöntemleri olabilir, bu nedenle arabirimlerde hiçbir yöntem impl sahip olmak yanlış bir fikirdir. "Ebeveyn-Çocuk" IS-A ilişkisi burada anahtardır. Ayrıca, "Paylaşılan özellikler" ile "Paylaşılan Özellikler" karşılaştırması. örneğin, Köpek iS-A Hayvan. Ama bir köpek de "
yürüyebilir

30

Zihninizde açık bir kavram varsa ne zaman ne yapacağınız çok basit bir şeydir.

Soyut sınıflar Türetilebilirken, Arayüzler Uygulanabilir. İkisi arasında bir fark var. Bir Abstract sınıfı türettiğinizde, türetilmiş sınıf ile temel sınıf arasındaki ilişki 'bir' ilişkidir. örneğin, bir köpek bir hayvandır, bir koyun bir hayvandır, bu türetilmiş bir sınıfın bazı özellikleri temel sınıftan miras aldığı anlamına gelir.

Arayüzlerin uygulanması için ilişki "olabilir". örneğin, bir köpek casus bir köpek olabilir. Bir köpek bir sirk köpeği olabilir. Bir köpek bir yarış köpeği olabilir. Bu, bir şey elde etmek için belirli yöntemleri uyguladığınız anlamına gelir.

Umarım netimdir.


11

İlişkisiz sınıflara ortak işlevsellik sağlayan bir şey oluşturuyorsanız, bir arabirim kullanın.

2.Hiyerarşiyle yakından ilişkili nesneler için bir şeyler oluşturuyorsanız, soyut bir sınıf kullanın.



7

Bunu koymanın en kısa yolu şöyle düşünüyorum:

Paylaşılan özellikler => soyut sınıf.
Paylaşılan işlevsellik => arayüz.

Ve daha az öz vermek gerekirse ...

Soyut Sınıf Örneği:

public abstract class BaseAnimal
{
    public int NumberOfLegs { get; set; }

    protected BaseAnimal(int numberOfLegs)
    {
        NumberOfLegs = numberOfLegs;
    }
}

public class Dog : BaseAnimal
{
    public Dog() : base(4) { }
}

public class Human : BaseAnimal 
{
    public Human() : base(2) { }
}

Hayvanlar ortak bir özelliğe sahip olduklarından - bu durumda bacak sayısı - bu paylaşılan özelliği içeren soyut bir sınıf yapmak mantıklıdır. Bu aynı zamanda söz konusu mülk üzerinde çalışan ortak kod yazmamızı sağlar. Örneğin:

public static int CountAllLegs(List<BaseAnimal> animals)
{
    int legCount = 0;
    foreach (BaseAnimal animal in animals)
    {
        legCount += animal.NumberOfLegs;
    }
    return legCount;
}

Arayüz Örneği:

public interface IMakeSound
{
    void MakeSound();
}

public class Car : IMakeSound
{
    public void MakeSound() => Console.WriteLine("Vroom!");
}

public class Vuvuzela : IMakeSound
{
    public void MakeSound() => Console.WriteLine("VZZZZZZZZZZZZZ!");        
}

Burada Vuvuzelas ve Cars'ın tamamen farklı şeyler olduğunu, ancak paylaştıkları işlevselliğe sahip olduklarını unutmayın: bir ses çıkarmak. Böylece, burada bir arayüz mantıklı. Ayrıca, programcıların ses çıkaran şeyleri ortak bir arayüz altında bir araya getirmelerine izin verecektir - IMakeSoundbu durumda. Bu tasarımla aşağıdaki kodu yazabilirsiniz:

List<IMakeSound> soundMakers = new List<ImakeSound>();
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Vuvuzela());

foreach (IMakeSound soundMaker in soundMakers)
{
    soundMaker.MakeSound();
}

Bunun ne elde edeceğini söyleyebilir misiniz?

Son olarak, ikisini birleştirebilirsiniz.

Kombine Örnek:

public interface IMakeSound
{
    void MakeSound();
}

public abstract class BaseAnimal : IMakeSound
{
    public int NumberOfLegs { get; set; }

    protected BaseAnimal(int numberOfLegs)
    {
        NumberOfLegs = numberOfLegs;
    }

    public abstract void MakeSound();
}

public class Cat : BaseAnimal
{
    public Cat() : base(4) { }

    public override void MakeSound() => Console.WriteLine("Meow!");
}

public class Human : BaseAnimal 
{
    public Human() : base(2) { }

    public override void MakeSound() => Console.WriteLine("Hello, world!");
}

Burada, herkesin BaseAnimalses çıkarmasını istiyoruz, ancak henüz uygulanmasını bilmiyoruz. Böyle bir durumda arayüz uygulamasını soyutlayabilir ve uygulamasını alt sınıflarına devredebiliriz.

Son bir nokta, soyut sınıf örneğinde farklı nesnelerin paylaşılan özellikleri üzerinde nasıl çalışabildiğimizi ve arayüz örneğinde farklı nesnelerin paylaşılan işlevselliğini nasıl çağırabildiğimizi hatırlıyor musunuz? Bu son örnekte her ikisini de yapabiliriz.


7

Arayüz üzerinden soyut bir sınıf ne zaman tercih edilmeli?

  1. Bir program / projenin ömrü boyunca bir temel sınıfı güncellemeyi planlıyorsanız, temel sınıfın soyut bir sınıf olmasını sağlamak en iyisidir
  2. Bir kişi, bir hiyerarşide yakından ilişkili nesneler için bir omurga oluşturmaya çalışıyorsa, soyut bir sınıf kullanmak son derece yararlıdır

Soyut sınıfa göre ne zaman bir arayüz tercih edilmeli?

  1. Büyük bir hiyerarşik çerçeve türü ile uğraşmıyorsa, arayüzler mükemmel bir seçim olacaktır.
  2. Soyut sınıflarla çoklu kalıtım desteklenmediğinden (elmas sorunu), arayüzler günü kurtarabilir

Neredeyse on yıllık eski bir sorunun 22. cevaba ihtiyacı olduğunu düşündüren şey nedir?
jonrsharpe

3
Soruya basit bir cevap aramamı sağlayan aynı düşünce türü.
Satya

1
FWIW, bu yanıtı gerçekten çok seviyorum.
Brent Rittenhouse

6

Sınıflar yalnızca bir temel sınıftan miras alabilir, bu nedenle bir grup sınıfa polimorfizm sağlamak için soyut sınıfları kullanmak istiyorsanız, hepsi bu sınıftan miras almalıdır. Soyut sınıflar, halihazırda uygulanmış üyeleri de sağlayabilir. Bu nedenle, soyut bir sınıfla belirli bir miktarda özdeş işlevsellik sağlayabilirsiniz, ancak bir arabirim ile olamaz.

Bileşenlerinize polimorfizm sağlamak için bir arabirim mi yoksa soyut bir sınıf mı kullanacağınıza karar vermenize yardımcı olacak bazı öneriler.

  • Bileşeninizin birden çok sürümünü oluşturmayı düşünüyorsanız, soyut bir sınıf oluşturun. Soyut sınıflar bileşenlerinizi sürümlendirmek için basit ve kolay bir yol sağlar. Temel sınıf güncelleştirildiğinde, tüm devralma sınıfları değişiklikle birlikte otomatik olarak güncelleştirilir. Öte yandan, arayüzler bu şekilde oluşturulduktan sonra değiştirilemez. Bir arayüzün yeni bir sürümü gerekiyorsa, tamamen yeni bir arayüz oluşturmalısınız.
  • Oluşturduğunuz işlevsellik çok çeşitli farklı nesnelerde faydalı olacaksa, bir arabirim kullanın. Soyut sınıflar öncelikli olarak yakından ilişkili nesneler için kullanılmalıdır, arayüzler ise ilgisiz sınıflara ortak işlevsellik sağlamak için en uygunudur.
  • Küçük, özlü işlevsellik parçaları tasarlıyorsanız, arabirimler kullanın. Büyük fonksiyonel birimler tasarlıyorsanız, soyut bir sınıf kullanın.
  • Bileşeninizin tüm uygulamaları arasında ortak, uygulamalı işlevsellik sağlamak istiyorsanız soyut bir sınıf kullanın. Soyut sınıflar sınıfınızı kısmen uygulamanıza izin verirken, arayüzler herhangi bir üye için uygulama içermez.

Kopyalandığı yer:
http://msdn.microsoft.com/en-us/library/scsyfw1d%28v=vs.71%29.aspx


UML'de birden fazla sınıf mirasını engelleyen hiçbir şey yoktur. Çoklu kalıtım UML tarafından değil, bir programlama dili ile belirlenir. Örneğin, Java ve C # 'da birden fazla sınıf mirasına izin verilmez, ancak C ++' da izin verilir.
BobRodes

@BobRodes: Nesne yönelimli çerçevelerin çeşitli kombinasyonlarda sağlayabileceği, ancak tüm kombinasyonlarda sağlayamayacağı bir dizi özellik vardır. Genelleştirilmiş çoklu kalıtım, gerçek örneğin herhangi bir üst türüne veya bununla desteklenen herhangi bir arabirim türüne doğrudan bir referans verebilme ve temel türleri ve türetilmiş türleri bağımsız olarak derleme ve çalışma zamanında bunlara katılma yeteneği dahil olmak üzere diğer bazı yararlı kombinasyonları engeller.
supercat

@supercat Sizinki, birden fazla miras kullanımından kaynaklanan bazı sorunların iyi bir açıklamasıdır. Bununla birlikte, UML'de bir diyagramda birden fazla sınıf mirasını engelleyen hiçbir şey yoktur. Yukarıdaki "Sınıflar sadece bir temel sınıftan miras alabilir ..." diye cevap veriyordum ki bu pek de öyle değil.
BobRodes

@BobRodes: Soru Java olarak etiketlendi. Java belirtilen özellikleri içerir ve bu nedenle "ölümcül elmas" üretemeyen çoklu kalıtım biçimleriyle sınırlıdır (aslında varsayılan arayüz uygulamalarını uygulama şekli ölümcül elması mümkün kılar).
supercat

@supercat Oh, tamam. Genellikle java etiketlerine bakmıyorum, bu yüzden en azından bir UML cevabı hakkında yorum yaptığımı düşündüğümü yazdım. Her durumda, yorumunuza katılıyorum.
BobRodes

3

Bu ifadelerden herhangi biri durumunuz için geçerliyse soyut sınıflar kullanmayı düşünün :

  1. Kodu yakından ilişkili birkaç sınıf arasında paylaşmak istiyorsunuz.
  2. Soyut sınıfınızı genişleten sınıfların birçok ortak yöntemi veya alanı olmasını veya genel (erişim korumalı ve özel gibi) erişim değiştiricileri gerektirmesini beklersiniz.
  3. Statik olmayan veya nihai olmayan alanları bildirmek istiyorsunuz. Bu, ait oldukları nesnenin durumuna erişebilecek ve bunları değiştirebilecek yöntemleri tanımlamanızı sağlar.

Bu ifadelerden herhangi biri durumunuz için geçerliyse arayüzleri kullanmayı düşünün :

  1. İlişkisiz sınıfların arayüzünüzü uygulamasını beklersiniz. Örneğin, Karşılaştırılabilir ve Klonlanabilir arabirimler, ilgisiz birçok sınıf tarafından uygulanır.
  2. Belirli bir veri türünün davranışını belirtmek istiyorsunuz, ancak davranışını kimin uyguladığından endişe etmiyorsunuz.
  3. Birden fazla mirastan yararlanmak istiyorsunuz.

Kaynak


2

Cevaplar diller arasında farklılık gösterir. Örneğin, Java'da bir sınıf birden çok arabirim uygulayabilir (devralma), ancak yalnızca bir soyut sınıftan devralma. Böylece arayüzler size daha fazla esneklik sağlar. Ancak bu C ++ için geçerli değildir.


2

Benim için, birçok durumda arayüzlerle giderdim. Ancak bazı durumlarda soyut dersleri tercih ederim.

OO'daki sınıflar genellikle uygulamaya atıfta bulunur. Arabirimlerle gittiğim çocuklara bazı uygulama ayrıntılarını zorlamak istediğimde soyut sınıflar kullanıyorum.

Tabii ki, soyut sınıflar sadece uygulamayı zorlamak için değil, aynı zamanda ilgili birçok sınıf arasında bazı detayları paylaşmak için de yararlıdır.


1

Bazı temel uygulamalar sağlamak için soyut bir sınıf kullanın.


1
Teşekkürler Sebastian. Peki ya temel bir uygulamaya sahip olmam gerekmiyorsa? Soyut bir sınıf ve arayüz aynı olmayacak mı o zaman aralarındaki tek fark bu ise? Neden burada bir fark var?
Chirantan

1
Çünkü bazı dillerde arayüzler yoktur - C ++.
jmucchiello

1

Java'da "sağlamak" işlevi için bir (soyut) sınıftan miras alabilir ve işlevselliği "sağlamak" için birçok arabirim uygulayabilirsiniz


lil 'hint: soyut bir sınıftan ve bir arayüzden miras almak istiyorsanız, soyut sınıfın arayüzü uyguladığından emin olun
Andreas Niedermair

1

Tamamen miras temelinde, açık bir şekilde torun, soyut ilişkiler (yani hayvan-> kedi) tanımladığınız ve / veya sanal veya kamuya açık olmayan mülklerin, özellikle paylaşılan durumun (Arayüzlerin destekleyemediği durumların mirasına) ihtiyaç duyduğunuz bir Özet kullanırsınız. ).

Yapabileceğiniz kalıtım üzerine kompozisyonu (bağımlılık enjeksiyonu yoluyla) denemeli ve desteklemelisiniz ve sözleşmeler olan arayüzlerin Abstracts'ın yapamayacağı şekilde ünite testini, endişelerin ayrılmasını ve (dil değiştirerek) çoklu kalıtımı desteklediğini unutmayın.


1

Arayüzlerin soyut sınıflardan daha iyi ücret aldığı ilginç bir yer, bir grup (ilgili veya ilgisiz) nesneye ekstra işlevsellik eklemeniz gerektiğidir. Onlara temel bir soyut sınıf veremezseniz (örneğin, sealedbir üst öğe veya zaten bir üst öğeye sahipseniz), onlara kukla (boş) bir arabirim verebilir ve ardından bu arabirim için uzantı yöntemleri yazabilirsiniz.


0

Bu çok zor bir çağrı olabilir ...

Verebileceğim bir işaretçi: Bir nesne çok sayıda arabirim uygulayabilirken, bir nesne yalnızca bir temel sınıfı devralabilirken (c # gibi modern bir OO dilinde, C ++ 'nın çoklu kalıtım olduğunu biliyorum - ama kaşlarını çatmadı mı?)


Çoklu kalıtsallık Mixin'in görünüşte uygulanmasına izin verir, iyi yazılmış Mixin'ler çalışmak için bir esinti ama gelmesi çok zor ve bir yere düşmeden yazmak zor. Mixin IMO olsa bir bütün olarak oldukça serin.
Martijn Laarman

Aslında yapmadım, çoklu kalıtsallık gerçekten emin bir tartışma kıvılcımı aramızda geeks kesinlikle aşağı itmek için hiçbir neden görmüyorum. Aslında cevabınızı iptal ettim.
Martijn Laarman

Yapmaya çalıştığım tek nokta, Mix in Single Inheritence (D: Tekil Devralma) dillerinde de yolların (C #, PHP, javascript) ancak çirkin davranışlar veya yapışkan sözdizimi ile mümkün olmasıdır. Mixin'leri çalışırken seviyorum ama yine de birden fazla kalıtımdan ya da değil mi daha fazla kararsızım.
Martijn Laarman

Bu cevap, bir tasarım farkından çok sözdizimsel bir farktır. Sanırım bir tasarım farkı istiyor
Pramod Setlur

0

Soyut bir sınıfın uygulamaları olabilir.

Bir arayüzün uygulamaları yoktur, sadece bir tür sözleşme tanımlar.

Dile bağlı bazı farklılıklar da olabilir: örneğin C # birden fazla mirasa sahip değildir, ancak bir sınıfa birden çok arabirim uygulanabilir.


"Bir tür sözleşme" derken, web servislerinde olduğu gibi mi demek istediniz?
Chirantan

Teknik olarak konuşursak, web hizmetleri arayüzlerle çalışmaz. Sözleşme ile, bir nesnenin kullanıcısı, o nesne üzerinde hangi yöntemlerin bulunduğunu bilir. Örneğin, bir arabirim IMouse bir Taşı yöntemi ve bir sol ve sağ fare düğmesi olayı olacaktır.
Gerrie Schenck

-1

Temel başparmak kuralı: "İsimler" için Abstract sınıfını ve "Fiiller" arayüzünü kullanın

Örn: carsoyut bir sınıftır ve driveonu bir arayüz yapabiliriz.


5
Bu mantıklı değil, aynı zamanda drivearabadaki işlevselliğini de koyabiliriz - bu soyut bir sınıftır.
Arslan Ali
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.