C # 'daki uzatma yöntemlerine sahip arabirimler yerine soyut sınıflar ne zaman kullanılır?


70

"Soyut sınıf" ve "arabirim" benzer kavramlardır; arabirim ikisinin daha soyut olmasını sağlar. Farklılaşan bir faktör, soyut sınıfların gerektiğinde türetilmiş sınıflar için yöntem uygulamaları sağlamasıdır. Bununla birlikte, C # 'da, bu farklılaşma faktörü, arayüz yöntemleri için uygulamaların sağlanmasına olanak tanıyan uzatma yöntemlerinin tanıtımıyla azaltılmıştır. Bir başka farklılaşma faktörü, bir sınıfın sadece bir soyut sınıfı miras alabilmesidir (yani, çoklu miras yoktur), ancak çoklu arayüzleri uygulayabilmesidir. Bu arayüzleri daha az kısıtlayıcı ve daha esnek hale getirir. Öyleyse, C # 'da, uzatma yöntemlerine sahip arabirimler yerine soyut sınıfları ne zaman kullanmalıyız?

Arabirim + uzantı yöntemi modelinin kayda değer bir örneği, IEnumerableçok sayıda uzantı yöntemi ile uygulanan her tür için sorgu işlevinin sağlandığı LINQ'dur.


2
Ayrıca 'Özellikler'i arayüzlerde de kullanabiliriz.
Gulshan

1
Genel bir OOD sorusu yerine C # 'a özgü gibi. (Diğer birçok OO dili uzatma yöntemlerine veya özelliklerine sahip değildir.)
Péter Török


4
Uzatma yöntemleri, soyut sınıfların çözdüğü problemi tam olarak çözmez, bu nedenle sebebi Java veya başka bir tek miras dilinden farklı değildir.
İş

3
Anahtar sınıf yöntemi uygulamaları için ihtiyaç vardır olmayan uzantısı yöntemleri azaltılmıştır. Uzantı yöntemleri özel üye alanlarına erişemez, sanal olarak ilan edilemez ve türetilmiş sınıflarda geçersiz kılınamaz.
zooone9243

Yanıtlar:


63

Uygulanacak sınıfın bir kısmına ihtiyacınız olduğunda. Kullandığım en iyi örnek, şablon yöntemi desenidir.

public abstract class SomethingDoer
{
    public void Do()
    {
        this.DoThis();
        this.DoThat();
    }

    protected abstract void DoThis();
    protected abstract void DoThat();
}

Böylece, Do () çağrıldığında nasıl uygulanacaklarının özelliklerini bilmeden atılacak adımları tanımlayabilirsiniz. Sınıflandırma, soyut yöntemleri uygulamalı, ancak Do () yöntemini uygulamamalıdır.

Eklenti yöntemleri, denklemin "sınıfın bir parçası olması gerekir" bölümünü mutlaka karşılamaz. Ek olarak, iirc, extension yöntemleri kamuya açık bir şey olamaz (görünebilir).

Düzenle

Soru, başlangıçta kredi verdiğimden daha ilginç. Daha fazla incelemeden sonra Jon Skeet , SO ile ilgili bir soruyu arayüzler + uzatma yöntemleri kullanmak lehine cevapladı . Ayrıca, potansiyel bir olumsuz , bu şekilde tasarlanmış bir nesne hiyerarşisine karşı yansıma kullanmaktır.

Şahsen, şu anda yaygın bir uygulamayı değiştirmenin yararını görmekte güçlük çekiyorum, fakat aynı zamanda bunu yapmanın çok az ya da hiç dezavantajı görmüyorum.

Bu şekilde birçok dilde Program sınıfları aracılığıyla programlamanın mümkün olduğu belirtilmelidir. Eklentiler, metodun sınıfa ait gibi görünmesini sağlamak için sadece sözdizimsel şekeri sağlar.


Beni yendi ..
Giorgi

1
Ancak Arayüzler ve uzatma yöntemleri ile aynı şey yapılabilir. Orada soyut sınıfta Do()tanımladığınız yöntemler gibi bir uzatma yöntemi olarak tanımlanacaktır. Ve türetilmiş sınıfların tanımları için ayrılan yöntemler DoThis(), ana arayüzün üyesi olacaktır. Arayüzlerle, çoklu uygulamaları / devralmayı destekleyebilirsiniz. Ve şunu görün- odetocode.com/blogs/scott/archive/2009/10/05/…
Gulshan

@Gulshan: Çünkü birden fazla şekilde yapılabilecek bir şey seçilen yolu geçersiz kılmaz. Arayüz kullanımında hiçbir avantaj yoktur. Anahtar sınıf kendisi bir arayüz. Birden fazla uygulamayı desteklemek için arayüzlere ihtiyacınız yoktur.
ThomasX

Ayrıca, arayüz + uzatma modelinin dezavantajları olabilir. Örneğin, Linq kütüphanesini alın. Bu harika, ancak bu kod dosyasında yalnızca bir kez kullanmanız gerekirse, tam Linq kitaplığı IntelliSense'te kod dosyanızdaki NEDEN IE IE'de kullanılabilir. Bu IDE performansını önemli ölçüde yavaşlatabilir.
KeithS

-1 çünkü, soyut sınıfların Şablon Yöntemi için arayüzlerden daha uygun olduğunu hiçbir şekilde göstermediniz
Benjamin Hodgson,

25

Her şey modellemek istediğiniz şeyle ilgili :

Soyut sınıflar miras yoluyla çalışır . Sadece özel temel sınıflar olarak, bir ilişki ilişkisi kurar.

Örneğin, bir köpek olduğunu dolayısıyla elimizdeki bir hayvan

class Dog : Animal { ... }

Gerçekten de genel bir hayvan yaratmanın (nasıl göründüğü gibi) gerçekten bir anlam ifade etmemesi nedeniyle , bu Animaltemel sınıfı yapıyoruz abstract- ama yine de bir temel sınıf. Ve Dogsınıf bir olmadan anlam ifade etmiyor Animal.

Öte yandan arayüzler farklı bir hikaye. Onlar miras kullanmayı ancak vermeyin polimorfizm ( edebilirsiniz da miras ile uygulanacak). Bir ilişki modeli değillerdir , fakat daha fazlasını destekliyorlar .

Örneğin IComparable- başka biriyle karşılaştırılmayı destekleyen bir nesne alın .

Bir sınıfın işlevselliği, uyguladığı arayüzlere bağlı değildir , arayüz sadece işlevselliğe erişmenin genel bir yolunu sağlar. Hala uygulayabilmemiz için hala Disposea Graphicsveya a FileStreamyapabiliriz IDisposable. Arabirim sadece ilgilidir birlikte yöntemleri.

Prensip olarak, bir sınıfın davranışını değiştirmeden sadece ona erişimi zenginleştirerek, tıpkı uzantılar gibi arayüzler ekleyebilir ve kaldırabilir. Nesne anlamsız hale geleceğinden bir temel sınıfı alamazsınız!


Temel bir sınıfı ne zaman özet olarak tutmayı tercih edersiniz?
Gulshan

1
@ Gülhan: Eğer öyleyse - nedense - aslında temel sınıfın bir örneğini yaratmanın bir anlamı yok. Bir Chihuahua ya da beyaz bir köpekbalığı “yaratabilirsin”, ancak daha fazla uzmanlaşmadan bir hayvan yaratamazsınız - böylece Animalsoyut yaparsınız . Bu abstracttüretilmiş sınıflar tarafından uzmanlaşmak için fonksiyonlar yazmanıza olanak sağlar . Ya da daha programlama açısından - muhtemelen oluşturmak için hiçbir anlam ifade etmez UserControl, ama bir şekilde Button olan bir UserControl, bu yüzden sınıf / AnaSınıf ilişki aynı tür var.
Dario

soyut yöntemlerin varsa, soyut sınıfa sahipsin. Ve bunları uygulamak için hiçbir değeri olmadığında sahip olduğunuz soyut yöntemler (hayvan için “go” gibi). Ve elbette, bazen soyut yaptığınızdan ziyade, bazı genel sınıftaki nesnelere izin vermek istemezsiniz.
Dainius

Gramer ve anlamsal olarak "B bir A" demek anlamlı olsaydı, A'nın soyut bir sınıf olması gerektiğini söyleyen hiçbir kural yoktur. Sınıftan gerçekten kaçınamayana kadar arayüzleri tercih etmelisiniz. Paylaşım kodu, arayüzlerin bileşimi vb. İle yapılabilir. Kendini garip miras ağaçları olan bir köşeye boyamaktan kaçınmayı kolaylaştırır.
sara,

3

Sadece yıllardır soyut dersleri (en azından yaratılmamış) kullanmadığımı fark ettim.

Soyut sınıf, arayüz ve uygulama arasında biraz garip bir canavardır. Soyut sınıflarda örümcek anlayışımı değiştiren bir şey var. Biri, arabirimin arkasındaki uygulamayı hiçbir şekilde (veya herhangi bir şekilde bağlantı kurmayacak şekilde) "ifşa etmemeli" diyebilirim.

Bir arabirim uygulayan sınıflar arasında ortak davranışa ihtiyaç duyulsa bile, soyut bir sınıf yerine bağımsız bir yardımcı sınıf kullanırdım.

Arayüzler için giderdim.


2
-1: Kaç yaşında olduğunuzdan emin değilim, ancak tasarım kalıplarını, özellikle de şablon yöntem kalıplarını öğrenmek isteyebilirsiniz. Tasarım desenleri sizi daha iyi bir programcı yapacak ve soyut sınıfların cehaletine son verecekler.
Jim G.

Karıncalanma hissi için de aynı şey. C # ve Java'nın ilk ve en önemli özelliği olan Sınıflar, bir tür oluşturma ve onu hemen bir uygulama için hemen zincirleme özelliğidir.
Jesse Millikan

2

IMHO, burada kavramların bir karışımı olduğunu düşünüyorum.

Sınıflar belirli bir miras çeşidi kullanırken, arayüzler farklı bir miras çeşidi kullanır.

Her iki miras türü de önemli ve faydalıdır ve her birinin avantajları ve dezavantajları vardır.

Baştan başlayalım.

Arayüzlü hikayeler C ++ ile çok uzun zaman önce başlıyor. 1980'lerin ortalarında, C ++ geliştirildiği zaman, arayüzlerin farklı bir tür olarak olduğu fikri henüz gerçekleşmedi (zamanla ortaya çıkacaktı).

C ++ 'a yalnızca sınıf mirası vardı, sınıflar tarafından kullanılan ve miras olarak adlandırılan miras türü.

GoF Kitabı tavsiyesini uygulayabilmek için: "Arayüz için programlamak ve uygulama için programlamak", C ++, C # 'da hangi arayüzlerin yapabileceğini (ve faydalı!) Yapabildiğini yapabilmek için soyut sınıfları ve çoklu uygulama mirasını destekledi .

C #, "Arayüz için programlama yapmak ve uygulama için değil" olmak üzere en az iki farklı yol sunmak için yeni bir tür, arayüzler ve yeni bir tür kalıtım, arayüz kalıtımı sunar: C # yalnızca Arayüz devralma ile çoklu kalıtım destekler (uygulama devralma ile değil).

Dolayısıyla, C # 'daki arayüzlerin arkasındaki mimari sebepler GoF tavsiyesidir.

Umarım bu yardımcı olabilir.

Saygılarımla, Gastón


1

Bir arabirime uzantı yöntemleri uygulamak, yalnızca ortak bir arabirimi paylaşabilecek sınıflar arasında ortak davranış uygulamak için kullanışlıdır. Bu sınıflar zaten mevcut olabilir ve başka yollarla uzantılara kapalı olabilir.

Yeni tasarımlar için arayüzlerde uzatma yöntemlerinin kullanılmasını tercih ederim. Tür hiyerarşisi için, uzatma yöntemleri, tüm hiyerarşiyi değişiklik için açmak zorunda kalmadan davranışı genişletmek için bir araç sağlar.

Bununla birlikte, uzatma yöntemleri özel uygulamaya erişememektedir; bu nedenle, özel bir uygulamayı genel bir arabirimin arkasına yerleştirmem gerekirse, soyut bir sınıf tek yol olacaktır.


Hayır, tek güvenli yol bu değil. Daha güvenli bir yol var. Bu, uzatma yöntemleridir. Müşteriler hiçbir zaman enfekte olmayacak. Bu yüzden arayüzlerden + uzatma yöntemlerinden bahsettim.
Gulshan

@Ed James Bence "daha az güçlü" = "daha esnek" Daha esnek bir arayüz yerine daha güçlü bir soyut sınıfı ne zaman seçersiniz?
Gulshan

@Ed James Asp.mvc'de uzatma yöntemleri en baştan kullanılmıştır. Bunun hakkında ne düşünüyorsun?
Gulshan

0

C # 'da çoklu kalıtımın desteklenmediğini düşünüyorum ve bu yüzden C #' da arabirim kavramının tanıtılmasının nedeni budur.

Soyut sınıflarda, çoklu kalıtım da desteklenmez. Bu yüzden soyut sınıfların mı yoksa arayüzlerin mi kullanılacağına karar vermek kolaydır.


Kesin olmak gerekirse, C # dilinde "arayüz" denilen saf soyut sınıflardır.
Johan Boulé

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.