Ne zaman arayüz oluşturulacağını nasıl bileceğim?


196

Geliştirme öğrenmemde arayüzler hakkında daha fazla bilgi edinmem gerektiğini hissettiğim bir noktadayım.

Onları sık sık okuyorum ama sanki onları kavrayamıyorum.

Şöyle örnekler okudum: 'Base', 'Run', 'GetLegs' gibi şeyler için IAnimal arayüzlü hayvan taban sınıfı - ama asla bir şey üzerinde çalışmadım ve "Hey bir arayüz kullanmalıyım" gibi hissettim buraya!"

Neyi kaçırıyorum? Neden kavramak benim için zor bir kavram? Ben sadece biri için somut bir ihtiyaç fark edemeyeceğimden korkuyorum - çoğunlukla onları anlamanın bazı eksik yönlerinden dolayı! Bir geliştirici olma konusunda üstüme bir şey kaçırmışım gibi hissettiriyor! Herkes böyle bir deneyim ve bir atılım olsaydı ben bu kavramı anlamak için bazı ipuçları takdir ediyorum. Teşekkür ederim.


Yanıtlar:


151

bu somut sorunu çözer:

4 farklı tipte a, b, c, d var. tüm kod üzerinde şöyle bir şey var:

a.Process();
b.Process();
c.Process();
d.Process();

Neden IProcessable uygulayamıyorlar ve

List<IProcessable> list;

foreach(IProcessable p in list)
    p.Process();

hepsi aynı şeyi yapan 50 sınıf türü eklediğinizde bu çok daha iyi ölçeklendirilir.


Başka bir somut sorun:

Hiç System.Linq.Enumerable 'a baktınız mı? IEnumerable uygulayan herhangi bir tür üzerinde çalışan bir ton genişletme yöntemi tanımlar. IEnumerable'ı uygulayan her şey temelde "Sıralanmamış bir foreach tipi kalıpta yinelemeyi destekliyorum" dediğinden, herhangi bir numaralandırılabilir tür için karmaşık davranışlar (Count, Max, Where, Select vb.) Tanımlayabilirsiniz.


2
Bu yardımcı olur. Process () yöntemi için yalnızca uygulama türlerine sahip olmak yerine bir arabirimin mevcut olmasının avantajı nedir?
user53885

Hepsi aynı taban türünde alt sınıflar olmadıkça veya arabirimi uygulamadıkça, aynı değişken p'yi kullanamazsınız.
Karl

Bir Process yöntemi ile 50 farklı sınıfa karşılık döküm yapmak zorunda değilsiniz. C # "ördek yazmayı" kullanmaz, bu nedenle A'nın Process () ve B'nin Process () olması, çağrı yapmanın genel bir yolu olmadığı anlamına gelmez. Bunun için bir Arayüze ihtiyacınız var.
user7116

sağ. Örnek daha anlamlı hale getirmek için "var" ı "IProcessable" olarak değiştirdim.
Jimmy

2
@Rogerio: Genel olmaya çalışıyordum. Mesele şu ki, "Process () işlevi olan bir şey olduğunda" ortak bir yöntem kümesini paylaşan şeyleriniz olduğunda "değildir. örnek kolayca değiştirilebilirforeach(IMyCompanyWidgetFrobber a in list) a.Frob(widget, context);
Jimmy

133

Jimmy'nin cevabını çok seviyorum, ama buna bir şeyler eklemem gerektiğini hissediyorum. Her şeyin anahtarı IProcess'teki "mümkün" mümkün. Arayüzü uygulayan nesnenin bir yeteneğini (veya özelliğini, ancak "iç kalite" anlamına gelir, C # özellikleri anlamında değil) ifade eder. IAnimal muhtemelen bir arayüz için iyi bir örnek değildir, ancak IWalkable, sisteminizde yürüyebilecek çok şey varsa iyi bir arayüz olabilir. Köpek, İnek, Balık, Yılan gibi Hayvandan türetilmiş sınıflarınız olabilir. İlk ikisi muhtemelen IWalkable'ı uygular, son ikisi yürümez, bu yüzden yapmazlar. Şimdi "Neden sadece Köpek ve İnek'ten türetilmiş başka bir üst sınıf olan WalkingAnimal'e değil?" Cevap, kalıtım ağacının dışında, robot gibi de yürüyebilen bir şeyiniz olduğunda. Robot IWalkable'ı uygulayacaktı, ancak muhtemelen Animal'den türeyemezdi. Eğer yürüyebilecek şeylerin bir listesini istiyorsanız,

Şimdi IWalkable'ı IPersistable gibi daha fazla yazılımla değiştirin ve benzetme gerçek bir programda gördüğünüze çok daha yakın hale gelir.


9
Geldiğini seviyorum - "Bu bir kabiliyeti gösterir". Yetenekleri tanımlamanız gerektiğinde arayüzlere gerçekten ihtiyaç duyulmaktadır çünkü temeller “Base” sınıfına bağlı kalmalıdır.
Ramiz Uddin

72

Aynı işlevselliğin uygulamaları farklı olduğunda arayüzler kullanın.

Ortak bir somut uygulamayı paylaşmanız gerektiğinde özet / temel sınıfları kullanın.


8
Birincisine polimorfizm denir. İkincisi yılanlar yağdır - sublcass sürece olan AnaSınıf, Sen miras üzerinde kompozisyon tercih edilmelidir (Liskov ikamesi ilkesinin ihlal yoktur).
Arnis Lapsa

@ArnisLapsa "Sublcass baseclass olmadığı sürece" ne demek istediğinizi tam olarak anlamıyorum. Bir alt sınıf ne zaman "baseclass" olmaz? ( isanahtar kelimedeki gibi)
Marc.2377

32

Bir arayüzü bir Sözleşme gibi düşünün. "Bu sınıflar bu kurallara uymalı" demenin bir yolu.

Bu yüzden IAnimal örneğinde, "IAnimal'i uygulayan sınıflarda Run, Walk vb.

Bu neden faydalı? Örneğin nesneye Run and Walk'u çağırabilmeniz gerektiğine dayanan bir işlev oluşturmak isteyebilirsiniz. Aşağıdakilere sahip olabilirsiniz:

public void RunThenWalk(Monkey m) {
    m.Run();
    m.Walk();
}

public void RunThenWalk(Dog d) {
    d.Run();
    d.Walk();
}

... ve koşabileceğini ve yürüyebileceğini bildiğiniz tüm nesneler için bunu tekrarlayın. Ancak, IAnimal arayüzünüzle işlevi aşağıdaki gibi bir kez tanımlayabilirsiniz:

public void RunThenWalk(IAnimal a) {
    a.Run();
    a.Walk();
}

Arabirime karşı programlama yaparak, temelde arabirimin amacını uygulamak için sınıflara güvenirsiniz. Örneğimizde, düşünce " nasıl umurumda değil onlar Çalıştır ve Walk sürece onlar çalıştırın ve Yürüme. Benim RunThenWalk yeter ki bu anlaşmayı yerine kadar geçerli olacak. Bir şey başka yaklaşık bilmeden gayet iyi fonksiyonları sınıf."

Bu soruda da iyi bir tartışma var .


1
Uygulama bağımsızlığını unutmayın. Bir Arayüz, temel fonksiyonun nasıl uygulandığına dikkat etmemesine izin verir, sadece Arayüz'ün söylediklerini yapar.
Matthew Brubaker

18

Çok endişelenme. Birçok geliştirici, nadiren bir arayüz yazmaya ihtiyaç duyacaktır. Sık sık .NET çerçevesinde bulunan arabirimleri kullanırsınız , ancak yakın zamanda bir tane yazma gereğini hissetmiyorsanız, bu konuda şaşırtıcı bir şey yoktur.

Birisine her zaman verdiğim örnek, bir Yelkenli sınıfınız ve bir Viper sınıfınız varsa. Sırasıyla Boat sınıfını ve Car sınıfını miras alırlar. Şimdi tüm bu nesneler arasında geçiş yapmanız ve Drive()yöntemlerini çağırmanız gerektiğini söyleyin . Aşağıdaki gibi bir kod yazabilirsiniz:

if(myObject is Boat)
    ((Boat)myObject).Drive()
else
    if (myObject is Car)
        ((Car)myObject).Drive()

Yazmak çok daha kolay olurdu:

((IDrivable)myObject).Drive()

16

Birden fazla tür için tek bir değişken kullanmak istediğinizde Jimmy'nin hakkı vardır, ancak bu türlerin tümü aynı yöntemi bir arabirim bildirimi yoluyla uygular. Daha sonra bunlara arayüz tipi değişkeninde ana yöntem çağırabilirsiniz.

Bununla birlikte, arayüzleri kullanmak için ikinci bir neden var. Proje mimarı uygulama kodlayıcısından farklı bir kişi olduğunda veya birkaç uygulama kodlayıcısı ve bir proje yöneticisi olduğunda. Sorumlu kişi bir sürü arabirim yazabilir ve sistemin birlikte çalıştığını görebilir ve ardından uygulama sınıflarıyla arabirimleri doldurmak için geliştiricilere bırakabilir. Bu, birden fazla kişinin uyumlu sınıflar yazmasını sağlamanın en iyi yoludur ve bunu paralel olarak yapabilirler.


15

Ordu benzetmesini seviyorum.

Çavuş bir yazılım geliştiricisi , müzisyen veya avukat olmanız umurunda değil . Asker
muamelesi görüyorsunuz .

uml

Bu var daha kolay o ile çalışıyor kişilerin belirli ayrıntıları ile rahatsız etmek değil çavuş için
asker soyutlamalar olarak tedavi herkes (... ve olanlar gibi davranmak başarısız olduğunda onları cezalandırmak).

İnsanların asker gibi davranabilme yeteneğine polimorfizm denir.

Arayüzler polimorfizme ulaşmaya yardımcı olan yazılım yapılarıdır.

Need basitlik Kişisel sorunun cevabı elde etmek için soyut ayrıntılara.

Etimolojik olarak "birçok form" anlamına gelen polimorfizm , bir temel sınıfın herhangi bir alt sınıfının bir nesnesini, temel sınıfın bir nesnesi gibi ele alma yeteneğidir. Dolayısıyla bir temel sınıfın birçok biçimi vardır: temel sınıfın kendisi ve alt sınıflarından herhangi biri.

(..) Bu, kodunuzu yazmanızı ve başkalarının anlamasını kolaylaştırır. Diğer alt sınıflar daha sonra tür ailesine eklenebileceğinden ve bu yeni alt sınıfların nesneleri de varolan kodla çalışacağından kodunuzu genişletilebilir hale getirir.


14

Deneyimlerime göre, alaycı bir çerçeveyle birim testi yapmaya başlayana kadar arayüz oluşturma itici gücü oluşmadı. Arayüzlerin kullanımının alay etmeyi çok daha kolay hale getireceği çok açık oldu (çünkü çerçeve sanal olan yöntemlere bağlıydı). Bir kez başladığımda, sınıfımın arayüzünü uygulamadan soyutlamanın değerini gördüm. Gerçek bir arayüz oluşturmasam bile, şimdi yöntemlerimi sanallaştırmaya çalışıyorum (geçersiz kılınabilecek kapalı bir arayüz sağlıyor).

Arayüzlere yeniden düzenleme iyi uygulamasını pekiştirmek için bulduğum başka birçok neden var, ancak birim test / alaycı şey pratik deneyimin "aha anını" sağlayan şeydi.

EDIT : Netleştirmek için, birim test ve alay ile her zaman iki uygulama var - gerçek, somut uygulama ve testte kullanılan alternatif bir sahte uygulama. İki uygulamanız olduğunda, arayüzün değeri belirginleşir - arayüz açısından onunla ilgilenin, böylece uygulamayı istediğiniz zaman değiştirebilirsiniz. Bu durumda sahte bir arayüzle değiştiriyorum. Sınıfım düzgün bir şekilde yapılandırılmışsa bunu gerçek bir arayüz olmadan yapabileceğimi biliyorum, ancak gerçek bir arayüz kullanmak bunu güçlendiriyor ve daha temiz hale getiriyor (okuyucu için daha net). Bu itici güç olmadan, sadece sınıflarımın çoğunun tek bir somut uygulaması olduğu için arayüzlerin değerini takdir edeceğimi sanmıyorum.


Yanlış sebeplerden dolayı doğru olan şey. Sizin durumunuzda - "Başlık arayüzleri" olarak adlandırılırsınız ve ağırlıklar eklenirse, basitlik elde edilir.
Arnis Lapsa

@Arnis - birim testi "yanlış bir nedendir", testlerdeki bağımlılıkları kaldırmak için sınıfları kolayca alay etmek "yanlış bir nedendir". Üzgünüm, ama katılmıyorum.
tvanfosson

1
testler, kod test edilip edilemezse geri bildirim sağlayarak tasarımı dolaylı olarak etkilemelidir . test edilebilirliği geliştirmek için genişletilebilirlik noktaları eklemek hile gibidir. Sanırım Mark Seeman en iyi bit.ly/esi8Wp
Arnis Lapsa

1
@Arnis - birim testlerinizde taklitler kullanıyor musunuz? Değilse, bağımlılıklara olan güveni nasıl kaldırabilirsiniz. Hiç DI kullanıyor musunuz? Birim testleri beni alaycı ve DI'yi kullanmaya itti; alay ve DI, sözleşmeleri hiçbir akademik anlayışın yapamayacağı şekilde tanımlamak için arayüzleri kullanma konusunda iyi uygulamanın değerini kanıtladı. TDD'yi benimsediğim için, kodum aksi halde olacağından çok daha az bağlı. Bence bu iyi bir şey.
tvanfosson

sadece doğal eklemler olarak adlandırılmayan ayrışmanın düşük bütünlüğe ve gereksiz karmaşıklığa yol açtığını söylemek.
Arnis Lapsa

10

Programlamada arabirimlerin uygun kullanımlarını görmenize yardımcı olabilecek bazı programlama dışı örnekler.

Elektrikli cihazlar ve elektrik ağı arasında bir arayüz var - bu fişlerin ve soketlerin şekli ve bunlar arasındaki voltajlar / akımlar hakkında bir dizi konvansiyon . Yeni bir elektrikli cihaz uygulamak istiyorsanız, fişiniz kurallara uyduğu sürece ağdan servis alabilir. Bu, genişletilebilirliği çok kolaylaştırır ve koordinasyon maliyetlerini ortadan kaldırır veya azaltır : elektrik sağlayıcınızı yeni cihazınızın nasıl çalıştığı konusunda bilgilendirmek ve yeni cihazınızı ağa nasıl bağlayacağınız konusunda ayrı bir anlaşma yapmak zorunda değilsiniz.

Ülkeler standart ray göstergelerine sahiptir. Bu, raylar bırakan mühendislik şirketleri ile raylar üzerinde çalışmak üzere tren inşa eden mühendislik şirketleri arasında bir işbölümüne izin verir ve demiryolu şirketlerinin tüm sistemi yeniden aramadan trenlerin yerini almasını ve yükseltmesini mümkün kılar .

Bir işletmenin bir müşteriye sunduğu hizmet bir arayüz olarak tanımlanabilir: iyi tanımlanmış bir arayüz , hizmeti vurgular ve araçları gizler . Bir posta kutusuna bir mektup koyduğunuzda, posta sisteminin mektubu belirli bir süre içinde teslim etmesini beklersiniz, ancak mektubun nasıl teslim edildiği konusunda hiçbir beklentiniz yoktur: bilmenize gerek yoktur ve posta hizmetinin esnekliği vardır gereksinimleri ve mevcut koşulları en iyi karşılayan teslimat araçlarını seçin . Bunun bir istisnası, müşterilerin havayolu seçebilmesidir - bu, modern bir bilgisayar programcısının tasarladığı bir arayüz değildir, çünkü uygulamanın çok fazla olduğunu ortaya koymaktadır.

Doğadan örnekler: Yiyorlar (), makesSound (), hamle (), vb. Örnekleri çok meraklı değilim. Doğru olan davranışları tanımlarlar, ancak etkileşimleri ve nasıl etkinleştirildiklerini açıklamazlar . Doğada etkileşimleri mümkün kılan arayüzlerin bariz örnekleri üreme ile ilgilidir, örneğin bir çiçek tozlaşmanın gerçekleşmesi için bir arıya belirli bir arayüz sağlar.


5

Bir .net geliştiricisi olarak tüm hayatınıza devam etmek ve asla kendi arayüzlerinizi yazmak tamamen mümkündür. Sonuçta, onlarsız onlarca yıl hayatta kaldık ve dillerimiz hala Turing-complete idi.

Neden arayüzlere ihtiyacınız olduğunu söyleyemem, ancak mevcut projemizde bunları nerede kullandığımızın bir listesini verebilirim:

  1. Eklenti modelimizde, eklentileri arabirime göre yükleriz ve bu arabirimi, eklenti yazarlarına uyacak şekilde sağlarız.

  2. Makineler arası mesajlaşma sistemimizde, mesaj sınıflarının tümü belirli bir arabirimi uygular ve arabirimi kullanarak "paketten çıkarılır".

  3. Konfigürasyon yönetim sistemimiz, konfigürasyon ayarlarını yapmak ve almak için kullanılan bir arayüz tanımlar.

  4. Kötü bir dairesel referans probleminden kaçınmak için kullandığımız bir arayüzümüz var. (Gerekmiyorsa bunu yapmayın.)

Bir kural varsa, bu bir is-a ilişkisi içinde birkaç sınıf gruplamak istediğinizde arabirimler kullanmak, ancak temel sınıfta herhangi bir uygulama sağlamak istemiyorum sanırım.


5

Bir kod örneği (en benim bir ekstra ile Andrew kombinasyonu -amaçlı-of-arayüzleri ne ), yani aynı zamanda birden fazla miras (c # ve hiçbir destek dillerde yerine soyut bir sınıf neden arabirimde bir durumda yapar java):

interface ILogger
{
    void Log();
}
class FileLogger : ILogger
{
    public void Log() { }
}
class DataBaseLogger : ILogger
{
    public void Log() { }
}
public class MySpecialLogger : SpecialLoggerBase, ILogger
{
    public void Log() { }
}

FileLogger ve DataBaseLogger'ın arabirime ihtiyaç duymadığına dikkat edin (Logger soyut taban sınıfı olabilir). Ancak, sizi bir temel sınıf kullanmaya zorlayan bir üçüncü taraf günlükçüsü kullanmanız gerektiğini düşünün (kullanmanız gereken korumalı yöntemleri ortaya koyduğunu varsayalım). Dil, birden fazla mirası desteklemediğinden soyut temel sınıf yaklaşımını kullanamazsınız.

Sonuç olarak: kodunuzda ekstra esneklik elde etmek için mümkün olduğunda bir arayüz kullanın. Uygulamanız daha az bağlı olduğundan değişiklik için daha iyi uyum sağlar.


4

Arabirimleri şimdi kullandım ve işte en son kullanımım (isimler genelleştirildi):

WinForm üzerinde benim iş nesnesine veri kaydetmek gereken bir sürü özel denetimler var. Bir yaklaşım, her kontrolü ayrı ayrı çağırmaktır:

myBusinessObject.Save(controlA.Data);
myBusinessObject.Save(controlB.Data);
myBusinessObject.Save(controlC.Data);

Bu uygulama ile ilgili sorun bir kontrol eklemek her zaman benim "Veri Kaydet" yöntemine gitmek ve yeni kontrol eklemek zorunda olmasıdır.

SaveToBusinessObject (...) yöntemine sahip bir ISaveable arabirimi uygulamak için denetimlerimi değiştirdim, böylece şimdi "Verileri Kaydet" yöntemim sadece denetimler aracılığıyla yineleniyor ve ISaveable olanı bulursa, SaveToBusinessObject çağırır. Şimdi yeni bir kontrole ihtiyaç duyulduğunda, birinin yapması gereken tek şey ISaveable'yi bu nesneye uygulamak (ve asla başka bir sınıfa dokunmamak).

foreach(Control c in Controls)
{
  ISaveable s = c as ISaveable;

  if( s != null )
      s.SaveToBusinessObject(myBusinessObject);
}

Arayüzlere çoğu zaman gerçekleşmemiş fayda, değişiklikleri yerelleştirmenizdir. Bir kez tanımlandıktan sonra, bir uygulamanın genel akışını nadiren değiştirirsiniz, ancak genellikle ayrıntı düzeyinde değişiklikler yaparsınız. Ayrıntıları belirli nesnelerde tuttuğunuzda, ProcessA'daki bir değişiklik ProcessB'deki bir değişikliği etkilemez. (Temel sınıflar da size bu avantajı sağlar.)

DÜZENLEME: Başka bir fayda eylemlerde özgüllüktür. Örneğimde olduğu gibi, tek yapmak istediğim veriyi kaydetmek; Ne tür bir kontrol olduğu ya da başka bir şey yapıp yapamayacağı umurumda değil - sadece verileri kontrole kaydedip kaydedemeyeceğimi bilmek istiyorum. Kaydetme kodumu oldukça açık hale getiriyor - metin, sayısal, boole veya herhangi bir şey olup olmadığını görmek için herhangi bir kontrol yok, çünkü özel kontrol tüm bunları ele alıyor.


4

Sınıfınız için bir davranışı zorlamanız gerektiğinde bir arabirim tanımlamalısınız.

Bir Hayvanın davranışı, Yürüme, Yeme, Koşma vb.

Diğer bir pratik örnek, ActionListener (veya Runnable) arayüzüdür. Belirli bir etkinliği izlemeniz gerektiğinde bunları uygularsınız. Bu nedenle, actionPerformed(Event e)sınıfınızdaki (veya alt sınıfınızdaki) yöntem için uygulamayı sağlamanız gerekir . Benzer şekilde, Runnable arabirimi için, public void run()yöntem için uygulama sağlarsınız .

Ayrıca, bu arabirimlerin herhangi bir sayıda sınıf tarafından uygulanmasını sağlayabilirsiniz.

Arabirimlerin (Java'da) kullanıldığı başka bir örnek, C ++ 'da sunulan çoklu kalıtımın uygulanmasıdır.


3
Lütfen Tanrı, arayüzler konusunda birden fazla miras gibi şeyleri söylemelerini durdurun. Sen YAPMAYIN bir sınıfta arabirim devralır. Sen UYGULAYABİLİRSİNİZ bunu.
Andrei Rînea

4

Uyumaya çalıştığınızda oluşabilecek sıkıntıları modellemek istediğinizi varsayın.

Arayüzlerden önceki model

resim açıklamasını buraya girin

class Mosquito {
    void flyAroundYourHead(){}
}

class Neighbour{
    void startScreaming(){}
}

class LampJustOutsideYourWindow(){
    void shineJustThroughYourWindow() {}
}

Gördüğünüz gibi, uyumaya çalıştığınızda birçok 'şey' sinir bozucu olabilir.

Arayüzsüz sınıfların kullanımı

Ancak bu sınıfları kullanmaya gelince bir sorunumuz var. Ortak hiçbir şeyleri yok. Her yöntemi ayrı ayrı çağırmanız gerekir.

class TestAnnoyingThings{
    void testAnnoyingThinks(Mosquito mosquito, Neighbour neighbour, LampJustOutsideYourWindow lamp){
         if(mosquito != null){
             mosquito.flyAroundYourHead();
         }
         if(neighbour!= null){
             neighbour.startScreaming();
         }
         if(lamp!= null){
             lamp.shineJustThroughYourWindow();
         }
    }
}

Arayüzlü model

Bu sorunun üstesinden gelmek için bir iterface tanıtabilirizresim açıklamasını buraya girin

interface Annoying{
   public void annoy();

}

Ve sınıfların içinde uygula

class Mosquito implements Annoying {
    void flyAroundYourHead(){}

    void annoy(){
        flyAroundYourHead();
    }
}

class Neighbour implements Annoying{
    void startScreaming(){}

    void annoy(){
        startScreaming();
    }
}

class LampJustOutsideYourWindow implements Annoying{
    void shineJustThroughYourWindow() {}

    void annoy(){
        shineJustThroughYourWindow();
    }
}

Arayüzlerle kullanım

Bu derslerin kullanımını çok daha kolaylaştıracak

class TestAnnoyingThings{
    void testAnnoyingThinks(Annoying annoying){
        annoying.annoy();
    }
}

Tamam, ama değil Neighbourve LampJustOutsideYourWindowuygulamak zorunda da Annoying?
Stardust

Evet, belirttiğiniz için teşekkürler. Bu değişiklikle bir düzenleme yaptım
Marcin Szymczak

2

Verilmesi en kolay örnek Ödeme İşlemcileri (Paypal, PDS vb.) Gibidir.

ProcessACH ve ProcessCreditCard yöntemlerine sahip bir arabirim IPaymentProcessor oluşturduğunuzu varsayalım.

Artık somut bir Paypal uygulaması uygulayabilirsiniz. Bu yöntemlerin PayPal'a özgü işlevler olarak adlandırılması.

Daha sonra başka bir sağlayıcıya geçmeniz gerektiğine karar verirseniz, bunu yapabilirsiniz. Yeni sağlayıcı için başka bir somut uygulama oluşturun. Bağlı olduğunuz tek şey arayüzünüz (sözleşme) olduğundan, uygulamanızı kullanan kodu değiştirmeden hangisini kullandığını değiştirebilirsiniz.


2

Ayrıca Mock birim testi (.Net) yapmanıza da izin verir. Sınıfınız bir arayüz kullanıyorsa, nesneyi birim testinizde alay edebilir ve mantığı kolayca test edebilirsiniz (veritabanına veya web servisine çarpmadan).

http://www.nmock.org/


2

.NET Framework derlemelerine göz atarsanız ve standart nesnelerden herhangi biri için temel sınıflara girerseniz, birçok arabirim (ISomeName olarak adlandırılan üyeler) fark edersiniz.

Arayüzler temel olarak büyük veya küçük çerçevelerin uygulanması içindir. Kendi çerçevemi yazmak istedikçe arayüzler hakkında da aynı şekilde hissettim. Ayrıca arayüzlerin anlaşılmasının çerçeveleri daha hızlı öğrenmeme yardımcı olduğunu buldum. Hemen hemen her şey için daha zarif bir çözüm yazmak istediğiniz anda, bir arayüzün çok mantıklı olduğunu göreceksiniz. Bir sınıfın iş için uygun kıyafetleri giymesine izin verme yöntemi gibi. Daha da önemlisi, arabirimler sistemlerin çok daha fazla kendi kendini belgelemesine izin verir, çünkü sınıf arabirimleri uyguladığında karmaşık nesneler daha az karmaşık hale gelir, bu da işlevselliğini sınıflandırmaya yardımcı olur.

Sınıflar, bir çerçeveye açıkça veya örtük olarak katılmak istediklerinde arayüzleri uygular. Örneğin, IDisposable, popüler ve kullanışlı Dispose () yöntemi için yöntem imzası sağlayan ortak bir arabirimdir. Bir çerçevede, sizin veya başka bir geliştiricinin bir sınıf hakkında bilmesi gereken tek şey, IDisposable uygularsa, o zaman ((IDisposable) myObject) .Dispose () öğesinin temizleme amacıyla çağrıldığını bilmenizdir.

KLASİK ÖRNEK: IDisposable arabirimini uygulamadan, C # 'da "using ()" anahtar kelime yapısını kullanamazsınız, çünkü parametre olarak belirtilen herhangi bir nesnenin dolaylı olarak IDisposable'a dönüştürülebilmesini gerektirir.

KARMAŞIK ÖRNEK: Daha karmaşık bir örnek System.ComponentModel.Component sınıfı olacaktır. Bu sınıf hem IDisposable hem de IComponent uygular. Hepsi olmasa da, kendileriyle ilişkilendirilmiş görsel bir tasarımcıya sahip .NET nesneleri, IDE'nin bileşenle etkileşime girebilmesi için IComponent uygular.

SONUÇ: .NET Framework'ü daha iyi tanıdıkça, Nesne Tarayıcısında veya .NET Reflector (ücretsiz) aracında ( http://www.red-gate.com ) yeni bir sınıfla karşılaştığınızda yapacağınız ilk şey / products / reflector / ) hangi sınıftan miras aldığını ve uyguladığı arayüzleri kontrol etmektir. .NET Reflector, Türetilmiş sınıfları da görmenizi sağladığı için Nesne Tarayıcısından daha iyidir. Bu, belirli bir sınıftan türetilen tüm nesneler hakkında bilgi edinmenize, böylece var olduğunu bilmediğiniz çerçeve işlevselliği hakkında potansiyel olarak öğrenmenize olanak tanır. Bu, .NET Framework'e güncellenmiş veya yeni ad alanları eklendiğinde özellikle önemlidir.


2

Birinci şahıs atış oyunu yaptığınızı düşünün. Oyuncunun seçim yapabileceği birden fazla silahı var.

GunBir işlevi tanımlayan bir arayüze sahip olabilirizshoot() .

GunSınıfın farklı alt sınıflarına ihtiyacımız ShotGun Snipervar.

ShotGun implements Gun{
    public void shoot(){
       \\shotgun implementation of shoot.
    } 
}

Sniper implements Gun{
    public void shoot(){
       \\sniper implementation of shoot.
    } 
}

Nişancı Sınıfı

Atıcı zırhındaki tüm silahlara sahiptir. ListBunu temsil edecek bir a oluşturalım .

List<Gun> listOfGuns = new ArrayList<Gun>();

Atıcı, silahını kullanarak, gerektiğinde ve fonksiyonunu kullanarak switchGun()

public void switchGun(){
    //code to cycle through the guns from the list of guns.
    currentGun = //the next gun in the list.
}

Yukarıdaki fonksiyonu kullanarak mevcut Tabancayı ayarlayabilir ve çağrıldığında sadece çağrı shoot()fonksiyonunu çağırabiliriz fire().

public void fire(){
    currentGun.shoot();
}

Çekim işlevinin davranışı, ekranın farklı uygulamalarına göre Gun arayüzün .

Sonuç

Bir sınıf işlevi başka bir sınıftan bir işleve bağlı olduğunda arabirim oluşturma uygulanan sınıfın örneğine (nesnesine) bağlı olarak davranışını değiştirmeye tabi olan .

örneğin sınıftan fire()gelen işlev, Shootertabancaların ( Sniper, ShotGun) işlevi yerine getirmesini bekler shoot(). Yani silahı ve ateşi değiştirirsek.

shooter.switchGun();
shooter.fire();

fire()İşlev davranışını değiştirdik .


1

Larsenal'ın söylediklerini genişletmek için. Arayüz, tüm uygulayıcı sınıfların izlemesi gereken bir sözleşmedir. Bu nedenle, sözleşmeye programlama adı verilen bir teknik kullanabilirsiniz. Bu, yazılımınızın uygulamadan bağımsız olmasını sağlar.


1

Arabirimler genellikle nesnelerin gösterebileceği bir davranış tanımlamak istediğinizde kullanılır.

.NET dünyasında bunun iyi bir örneği, el ile serbest bırakılması gereken sistem kaynaklarını kullanan tüm Microsoft sınıflarında kullanılan IDisposable arabirimidir. Bunu uygulayan sınıfın Dispose () yöntemine sahip olması gerekir.

(Dispose () yöntemi, yalnızca s üzerinde çalışan VB.NET ve C # için dil yapısı kullanılarak da çağrılır IDisposable)

Bir nesnenin TypeOf ... Is(VB.NET), is(C #), instanceof(Java) gibi yapıları kullanarak belirli bir arabirim uygulayıp uygulamadığını kontrol edebileceğinizi unutmayın .


1

Muhtemelen birkaç kişinin cevapladığı gibi, bu davranışları aynı şekilde uygulamayan sınıflar arasındaki belirli davranışları uygulamak için arayüzler kullanılabilir. Yani bir arayüz uygulayarak sınıfınızın arayüzün davranışına sahip olduğunu söylüyorsunuz. IAnimal arabirimi tipik bir arabirim olmaz çünkü Köpek, Kedi, Kuş, vb. Sınıflar hayvan türleridir ve muhtemelen onu genişletmelidir, bu da bir kalıtım vakasıdır. Bunun yerine, bir arayüz bu durumda IRunnable, IFlyable, ITrainable, vb. Gibi hayvan davranışlarına benzeyecektir.

Arayüzler birçok şey için iyidir, anahtar şeylerden biri takılabilirliktir. Örneğin, List parametresine sahip bir yöntemin bildirilmesi, Liste arabirimini uygulayan herhangi bir şeyin aktarılmasına izin vererek geliştiricinin bir ton kodu yeniden yazmak zorunda kalmadan daha sonra farklı bir listeyi kaldırmasına ve takmasına olanak tanır.

Asla arayüz kullanamayabilirsiniz, ancak bir projeyi sıfırdan, özellikle bir çeşit çerçeve tasarlıyorsanız, muhtemelen bunlara aşina olmak istersiniz.

Coad, Mayfield ve Kern'in Java Design'daki arabirimler hakkındaki bölümünü okumanızı tavsiye ederim . Ortalama tanıtım metninden biraz daha iyi açıklarlar. Java kullanmıyorsanız, bölümün başlangıcını okuyabilirsiniz, temel olarak kavramlar.


1

Sisteminize esneklik katan tüm programlama teknikleri gibi arayüzler de bir miktar karmaşıklık katar. Genellikle harikalar ve her yerde kullanabilirsiniz (tüm sınıflarınız için bir arabirim oluşturabilirsiniz) - ancak bunu yapmak, bakımı daha zor olacak daha karmaşık bir sistem yaratabilirsiniz.

Burada her zamanki gibi bir değiş tokuş var: sürdürülebilirlik üzerinde esneklik. Hangisi daha önemli? Cevap yok - projeye bağlı. Ama sadece her yazılımın bakımının yapılması gerektiğini unutmayın ...

Benim tavsiyem: gerçekten ihtiyacınız olana kadar arayüz kullanmayın. (Visual Studio ile varolan bir sınıftan bir arabirimi 2 saniye içinde ayıklayabilirsiniz - bu yüzden acele etmeyin.)

Bunu söyledikten sonra, ne zaman bir arayüz oluşturmalısınız?

Aniden bir yöntemi yeniden düzenlediğimde yaparım iki veya daha fazla benzer sınıfı işlemek gereken . Daha sonra bir arabirim oluşturur, bu arabirimi iki (veya daha fazla) benzer sınıfa atar ve yöntem parametre türünü değiştiririm (sınıf türünü arabirim türüyle değiştirir).

Ve işe yarıyor: o)

Bir istisna: nesneleri ne zaman alay edeceğim, arayüzün kullanımı çok daha kolay. Bu yüzden sadece bunun için arayüz oluşturuyorum.

PS: "arayüz" yazdığımda, "arayüz sınıfı" dahil, herhangi bir temel sınıfın arayüzü "demek istiyorum. Soyut sınıfların genellikle saf arayüzlerden daha iyi bir bahis olduğunu unutmayın, çünkü onlara mantık ekleyebilirsiniz.

Saygılarımızla, Sylvain.


1

Bir kütüphane geliştiricisi (diğer kodlayıcıları kodlayan biri) olduğunuzda arayüzler belirginleşecektir . Çoğumuz uygulama geliştiricileri olarak başlıyoruz mevcut API'ları ve programlama kitaplıklarını kullandığımız .

Arayüzlerin bir sözleşme olduğu aynı satır boyunca , hiç kimse, Arayüzlerin kodunuzun bazı bölümlerini kararlı hale getirmenin harika bir yolu olduğunu söylemedi . Bu, bir ekip projesi olduğunda (veya diğer geliştiriciler tarafından kullanılan kodu geliştirirken) özellikle yararlıdır . İşte size somut bir senaryo:

Bir ekipte kod geliştirirken , diğerleri muhtemelen yazdığınız kodu kullanacaktır. (Kararlı) arayüzlerinize kod yazdıklarında en mutlu olacaklardır ve ekibinizin kodunu kırmadan uygulamalarınızı (arayüzün arkasına gizlenmiş) değiştirme özgürlüğünüz olduğunda mutlu olacaksınız. Bilgi gizlemenin bir çeşididir (arayüzler herkese açıktır, uygulamalar istemci programcılardan gizlenmiştir). Korunan varyasyonlar hakkında daha fazla bilgi edinin .

Ayrıca bir Arabirime kodlama ile ilgili bu soruya bakın .


1

Bir arayüz kullanmak için pek çok amaç vardır.

  1. Polimorfik davranışta kullanın. Bir alt sınıfın belirli yöntemlerini, alt sınıfla ilgili başvurusu olan bir arabirimle çağırmak istediğiniz yer.

  2. En yaygın kullanım gibi gerekli olan tüm yöntemleri uygulamak için sınıflarla sözleşme yapmak, arabirimi devralan bir DLL üzerinde bir sarıcı sınıfın üretildiği COM nesneleriyle; bu yöntemler sahne arkası çağrılır ve sadece bunları uygulamak gerekir, ancak sadece maruz oldukları arabirimi aracılığıyla bildiğiniz COM DLL tanımlandığı gibi aynı yapı ile.

  3. Bir sınıfa belirli yöntemler yükleyerek bellek kullanımını azaltmak için. Üç iş nesneniz varsa ve bunlar tek bir sınıfta uygulandıysa, üç arabirim kullanabilirsiniz.

Örneğin IUser, IOrder, IOrderItem

public interface IUser()
{

void AddUser(string name ,string fname);

}

// Same for IOrder and IOrderItem
//


public class  BusinessLayer: IUser, IOrder, IOrderItem

{    
    public void AddUser(string name ,string fname)
    {
        // Do stuffs here.
    }

    // All methods from all interfaces must be implemented.

}

Yalnızca bir kullanıcı eklemek istiyorsanız, şunu yapın:

IUser user = new (IUser)BusinessLayer();

// It will load  all methods into memory which are declared in the IUser interface.

user.AddUser();
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.