“Bir arayüze program yapmak” ne demektir?


814

Bunun birkaç kez bahsedildiğini gördüm ve bunun ne anlama geldiğinden emin değilim. Bunu ne zaman ve neden yapardın?

Arayüzlerin ne yaptığını biliyorum, ancak bu konuda net olmadığım gerçeği, bunları doğru bir şekilde kullanmayı kaçırdığımı düşündürüyor.

Sadece eğer öyle olsaydı:

IInterface classRef = new ObjectWhatever()

Uygulayan herhangi bir sınıfı kullanabilir IInterfacemisiniz? Ne zaman yapman gerekir? Düşünebileceğim tek şey, bir yönteminiz varsa ve uygulanması dışında hangi nesnenin geçeceğinden emin değilseniz IInterface. Bunu ne sıklıkta yapmanız gerektiğini düşünemiyorum.

Ayrıca, bir arabirimi uygulayan bir nesneyi alan bir yöntemi nasıl yazabilirsiniz? Mümkün mü?


3
Hatırlayabiliyorsanız ve programınızın optimal olması gerekiyorsa, derlemeden hemen önce gerçek uygulama için Arayüz bildirimini değiştirmek isteyebilirsiniz. Bir arayüz kullanmak gibi bir performans hit verir dolaylı bir seviye ekler. Programlanmış kodunuzu arabirimlere dağıtın ...
Ande Turner

18
@Ande Turner: bu kötü bir tavsiye. 1). "Programınızın optimal olması gerekiyor" arayüzleri değiştirmek için iyi bir neden değil! Sonra "Programlanmış kodunuzu arabirimlere dağıtın ..." diyorsunuz, böylece verilen gereksinimi (1) daha sonra en uygun olmayan kodu serbest bırakmanızı tavsiye ediyorsunuz?!?
Mitch Wheat

74
Buradaki cevapların çoğu doğru değil. "Arayüz anahtar sözcüğünü kullan" anlamına gelmez, hatta bu anlamına gelmez. Arayüz, bir şeyin nasıl kullanılacağına dair bir spekstir - sözleşme ile eşanlamlıdır (yukarıya bakın). Bundan ayrı olarak uygulama, yani sözleşmenin nasıl yerine getirildiği. Sadece yöntem / türün garantilerine karşı programlayın, böylece yöntem / tür hala sözleşmeye uyacak şekilde değiştirildiğinde, kodu kullanarak kodu kırmaz.
jyoungdev

2
@ apollodude217 aslında tüm sayfadaki en iyi cevaptır. En azından başlıktaki soru için, burada en az 3 oldukça farklı soru olduğu için ...
Andrew Spencer

4
Bunun gibi sorularla ilgili temel sorun, "bir arayüze programlamanın" "her şeyi soyut bir arayüze sarması" anlamına geldiğini varsayar.
Jonathan Allen

Yanıtlar:


1633

Arayüzler ve gevşek bağlantı kodu, kontrolün ters çevrilmesi ve benzeri konular hakkında her türlü ayrıntıya giren bu soruların bazı harika cevapları var. Oldukça kafa karıştırıcı tartışmalar var, bu yüzden bir arayüzün neden faydalı olduğunu anlamak için işleri biraz parçalama fırsatını kullanmak istiyorum.

Arayüzlere ilk kez maruz kalmaya başladığımda, onların ilgileri hakkında da kafam karıştı. Onlara neden ihtiyacın olduğunu anlamadım. Java veya C # gibi bir dil kullanıyorsanız, zaten mirasımız var ve arayüzleri daha zayıf bir miras ve düşünce biçimi olarak gördüm , "neden rahatsız oluyorsunuz?" Haklı olduğum bir anlamda, arayüzleri bir çeşit zayıf kalıtım biçimi olarak düşünebilirsiniz, ancak bunun ötesinde, nihayetinde, bunların sergilediği ortak özellikleri veya davranışları sınıflandırmanın bir aracı olarak düşünerek bir dil yapısı olarak kullanımlarını anladım. potansiyel olmayan birçok nesne sınıfı.

Örneğin - bir SIM oyununuz olduğunu ve aşağıdaki sınıflara sahip olduğunuzu varsayalım:

class HouseFly inherits Insect {
    void FlyAroundYourHead(){}
    void LandOnThings(){}
}

class Telemarketer inherits Person {
    void CallDuringDinner(){}
    void ContinueTalkingWhenYouSayNo(){}
}

Açıkçası, bu iki nesnenin doğrudan miras açısından hiçbir ortak yanı yoktur. Ama ikisinin de sinir bozucu olduğunu söyleyebilirsiniz.

Diyelim ki oyunumuz , akşam yemeği yerken oyun oyuncusunu rahatsız eden bir tür rastgele şeye sahip olmalı . Bu bir HouseFlyveya bir Telemarketerveya her ikisi de olabilir - ancak tek bir işlevle her ikisine de nasıl izin veriyorsunuz? Ve her bir farklı nesne türünü “sinir bozucu şeylerini” aynı şekilde yapmasını nasıl istersiniz?

Sandığından anahtarı, hem olmasıdır Telemarketerve HouseFlyortak bir gevşek onları modelleme açısından benzemiyoruz olmasına rağmen davranışını yorumlanır. Şimdi, her ikisinin de uygulayabileceği bir arayüz yapalım:

interface IPest {
    void BeAnnoying();
}

class HouseFly inherits Insect implements IPest {
    void FlyAroundYourHead(){}
    void LandOnThings(){}

    void BeAnnoying() {
        FlyAroundYourHead();
        LandOnThings();
    }
}

class Telemarketer inherits Person implements IPest {
    void CallDuringDinner(){}
    void ContinueTalkingWhenYouSayNo(){}

    void BeAnnoying() {
        CallDuringDinner();
        ContinueTalkingWhenYouSayNo();
    }
}

Artık her biri kendi tarzında sinir bozucu olabilecek iki sınıfımız var. Ve aynı temel sınıftan türetmeleri ve ortak doğal özellikleri paylaşmaları gerekmez - sadece sözleşmeyi yerine getirmeleri gerekir IPest- bu sözleşme basittir. Sadece yapman gerek BeAnnoying. Bu bağlamda, aşağıdakileri modelleyebiliriz:

class DiningRoom {

    DiningRoom(Person[] diningPeople, IPest[] pests) { ... }

    void ServeDinner() {
        when diningPeople are eating,

        foreach pest in pests
        pest.BeAnnoying();
    }
}

Burada bir dizi diners ve bir dizi zararlı kabul eden bir yemek odamız var - arayüzün kullanımını not edin. Bu, küçük dünyamızda pestsdizinin bir üyesinin aslında bir Telemarketernesne veya bir HouseFlynesne olabileceği anlamına gelir .

ServeDinnerAkşam yemeği sunulmaktadır ve yemek odasında halkımız yiyeceğim zaman yöntemi denir. Küçük oyunumuzda, haşerelerimizin işini yaptıkları zaman - her haşere IPestarayüz yoluyla can sıkıcıdır . Bu şekilde, her ikisine de kolayca sahip olabilir Telemarketersve HouseFlyskendi yollarının her birinde sinir bozucu olabiliriz - sadece DiningRoomhaşere olan nesnede bir şeyimiz olmasını önemsiyoruz, ne olduğunu gerçekten umursamıyoruz ve hiçbir şeyleri olamazdı. diğer ile ortak.

Bu çok yalancı sahte kod örneği (tahmin ettiğimden çok daha uzun süredir sürüklendi), nihayet benim için bir arayüz kullanabileceğimiz açısından ışığı açan şeyi göstermeyi amaçlıyor. Örneğin sersemliği için şimdiden özür dilerim, ancak anlayışınıza yardımcı olacağını umuyorum. Ve emin olmak için, burada aldığınız diğer gönderilen cevaplar gerçekten bugün tasarım desenleri ve geliştirme metodolojilerinde arayüzlerin kullanımının gamını kapsamaktadır.


3
Dikkate alınması gereken başka bir şey, bazı durumlarda "can sıkıcı" olabilecek şeyler için bir arayüze sahip olmanın ve BeAnnoyingno-op olarak çeşitli nesnelerin uygulanmasının yararlı olabileceğidir ; Bu arayüz yerine mevcut olabilir veya rahatsız edici şeyler için bir arayüz, ek olarak (hem arayüzler varsa, "şeyler vardır can sıkıcı" arayüz "şeylerden alması gerektiğini olabilir arayüzü can sıkıcı"). Bu tür arayüzleri kullanmanın dezavantajı, uygulamaların "sinir bozucu" sayıda saplama yöntemi uygulamakla yükümlü olabilmesidir. Avantajı bu ...
Supercat

4
Yöntemlerin soyut yöntemleri temsil etmesi amaçlanmamıştır - bunların uygulanması, arayüzlere odaklanan soru ile ilgisizdir.
Peter Meyer

33
IPest gibi enkapsüle edici davranışlar, herkesin bu konuda daha fazla malzeme takip etmekle ilgilenmesi durumunda strateji modeli olarak bilinir ...
nckbrz

9
İlginçtir ki, içindeki nesneler IPest[]IPest referansları BeAnnoying()olduğu için bu yönteme sahip oldukları için çağırabileceğinizi , ancak başka yöntemleri kadro olmadan çağıramazsınız. Ancak, her nesneye bireysel BeAnnoying()yöntem çağrılır.
D. Ben Knoble

4
Çok iyi bir açıklama ... Sadece ihtiyacım Ben gevşek miras mekanizması çeşit olmanın arayüzleri duymadım, ama bunun yerine normal Python sen, örneğin (arayüzleri tanımlamak için kötü bir mekanizma olarak kullanılan miras biliyorum: Burada söylemek her zaman yapın).
Carlos H Romano

283

Öğrencilere verdiğim özel örnek, onların

List myList = new ArrayList(); // programming to the List interface

onun yerine

ArrayList myList = new ArrayList(); // this is bad

Bunlar kısa bir programda tamamen aynı görünür, ancak programınızda myList100 kez kullanmaya devam ederseniz bir fark görmeye başlayabilirsiniz. İlk bildirim, yalnızca arabirim myListtarafından tanımlanan yöntemleri çağırmanızı sağlar List(bu nedenle ArrayListbelirli bir yöntem yoktur ). Arayüze bu şekilde programladıysanız, daha sonra gerçekten ihtiyacınız olduğuna karar verebilirsiniz.

List myList = new TreeList();

ve kodunuzu yalnızca bir noktada değiştirmeniz gerekir. Kodunuzun geri kalanının , arabirime programladığınız için uygulamayı değiştirerek kırılacak hiçbir şey yapmadığını zaten biliyorsunuz .

Yöntem parametreleri ve dönüş değerleri hakkında konuşurken faydaları daha da açıktır (sanırım). Örneğin bunu ele alalım:

public ArrayList doSomething(HashMap map);

Bu yöntem bildirimi sizi iki somut uygulamaya ( ArrayListve HashMap) bağlar . Bu yöntem diğer kodlardan çağrıldığında, bu türlerde yapılacak herhangi bir değişiklik muhtemelen arama kodunu da değiştirmeniz gerekeceği anlamına gelir. Arayüzlere programlamak daha iyi olur.

public List doSomething(Map map);

Şimdi ne tür Listgeri döndüğünüz ya da ne tür Mapbir parametre olarak aktarıldığınız önemli değil. doSomethingYöntemin içinde yaptığınız değişiklikler sizi arama kodunu değiştirmeye zorlamaz.


Yorumlar uzun tartışmalar için değildir; bu sohbet sohbete taşındı .
Yvette

Çok açık bir açıklama. Very helpful
samuel luswata

"İlk bildirim, yalnızca myList liste listesi arabirimi (yani hiçbir ArrayList belirli yöntemler) tarafından tanımlanan yöntemleri çağırmak sağlar. Bu arabirimi bu şekilde programladıysanız, daha sonra size List myList = new TreeList () öğesine gerçekten ihtiyacınız olduğuna karar verebilir ve kodunuzu yalnızca bir noktada değiştirmeniz gerekir. " Belki yanlış anladım, "Sadece myList'teki yöntemleri çağırmanızı sağlar" istiyorsanız ArrayList'i neden TreeList olarak değiştirmeniz gerektiğini merak ediyorum.
user3014901

1
@ user3014901 Kullandığınız liste türünü değiştirmek istemenizin birçok nedeni olabilir. Örneğin, daha iyi bir arama performansı olabilir. Mesele şu ki, Liste arayüzüne program yaparsanız, kodunuzu daha sonra farklı bir uygulamaya değiştirmeyi kolaylaştırır.
Kertenkele Bill

73

Bir arabirime programlama yapmak, "Bu işlevselliğe ihtiyacım var ve nereden geldiğini umursamıyorum" diyor.

(Java'da) ve somut sınıflara Listkarşı arabirimi düşünün . Eğer tek umurumda yineleme yoluyla erişmeliyim birden fazla veri öğeleri içeren bir veri yapısı olması, ben bir seçim olacaktır (ve bu zamanın% 99). Listenin her iki ucundan da sürekli zaman ekleme / silme ihtiyacım olduğunu biliyorsanız, somut uygulamayı seçebilirim (veya büyük olasılıkla Kuyruk arayüzünü kullanabilirim ). İndeks ile rastgele erişime ihtiyacım olduğunu bilsem, somut sınıfı seçerdim.ArrayListLinkedListListLinkedListArrayList


1
yani hem yapılanlarla nasıl yapılan arasındaki bağımsızlığa tamamen katılıyoruz. Bir sistemi bağımsız bileşenler arasında bölümlere
ayırarak

38

Arabirimleri kullanmak, sınıflarınız arasındaki gereksiz bağlantıları kaldırmanın yanı sıra kodunuzu kolayca test edilebilir hale getirmede önemli bir faktördür. Sınıfınızdaki işlemleri tanımlayan bir arabirim oluşturarak, bu işlevselliği kullanmak isteyen sınıfların, uygulayıcı sınıfınıza doğrudan bağlı kalmadan onu kullanma yeteneğine izin vermiş olursunuz. Daha sonra farklı bir uygulamayı değiştirmeye ve kullanmaya karar verirseniz, kodun yalnızca uygulamanın somutlaştırıldığı kısmını değiştirmeniz gerekir. Kodun geri kalanının değişmesi gerekmez, çünkü bu uygulama sınıfına değil, arabirime bağlıdır.

Bu birim testleri oluştururken çok faydalıdır. Test edilen sınıfta, arayüze bağımlıdır ve kurucu veya bir özellik ayarlayıcı aracılığıyla arayüzün bir örneğini sınıfa (veya gerektiğinde arayüzün örneklerini oluşturmasına izin veren bir fabrikaya) enjekte edersiniz. Sınıf, yöntemlerinde sağlanan (veya oluşturulan) arabirimi kullanır. Testlerinizi yazmaya başladığınızda, arayüzü taklit edebilir veya taklit edebilir ve birim testinizde yapılandırılan verilerle yanıt veren bir arayüz sağlayabilirsiniz. Bunu yapabilirsiniz çünkü test altındaki sınıfınız somut uygulamanızla değil, yalnızca arayüzle ilgilidir. Sahte veya sahte sınıfınız dahil, arabirimi uygulayan herhangi bir sınıf bunu yapacaktır.

EDIT: Aşağıda Erich Gamma, "Bir uygulama değil, bir arabirim için Program" sözünü tartıştığı bir makale bağlantısı.

http://www.artima.com/lejava/articles/designprinciples.html


3
Lütfen, bu röportajı tekrar okuyun: Gamma elbette JOA veya C # özel sınıf (ISomething) değil OO arayüz kavramı hakkında konuşuyordu. Sorun şu ki, çoğu insan anahtar kelimeden bahsediyordu, bu yüzden şimdi çok fazla kullanılmayan arayüzümüz var (ISomething).
Sylvain Rodrigue

Çok güzel bir röportaj. Lütfen, gelecekteki okuyucular için dikkatli olun, röportajda dört sayfa vardır. Görmeden önce tarayıcıyı neredeyse kapatırdım.
Reklam Infinitum

38

Bir arayüze programlamanın Java veya .NET'te gördüğümüz gibi soyut arayüzlerle hiçbir ilgisi yoktur. OOP konsepti bile değil.

Bunun anlamı, bir nesnenin veya veri yapısının iç kısımlarıyla uğraşmak değildir. Verilerinizle etkileşim kurmak için Özet Program Arayüzü veya API'yı kullanın. Java veya C # 'da bu, ham alan erişimi yerine genel özelliklerin ve yöntemlerin kullanılması anlamına gelir. C için bu, ham işaretçiler yerine işlevlerin kullanılması anlamına gelir.

EDIT: Ve veritabanları ile doğrudan tablo erişimi yerine görünümleri ve saklı yordamlar kullanmak anlamına gelir.


5
En iyi cevap. Gamma burada benzer bir açıklama yapar: artima.com/lejava/articles/designprinciples.html (bkz. Sayfa 2). OO konseptine atıfta bulunuyor, ancak haklısınız: bundan daha büyük.
Sylvain Rodrigue

36

Kontrolün İnversiyonuna bakmalısınız:

Böyle bir senaryoda, bunu yazmazsınız:

IInterface classRef = new ObjectWhatever();

Böyle bir şey yazarsınız:

IInterface classRef = container.Resolve<IInterface>();

Bu, containernesnede kural tabanlı bir düzene girer ve ObjectWhatever olabilecek gerçek nesneyi sizin için oluşturur. Önemli olan, bu kuralı başka bir tür nesne kullanan bir şeyle değiştirebilmeniz ve kodunuzun hala işe yarayacağıdır.

IoC'yi tablodan çıkarırsak, belirli bir şey yapan bir nesneyle konuşabileceğini bilen bir kod yazabilirsiniz , ancak hangi nesne türünü veya nasıl yaptığını değil.

Parametreleri geçerken bu kullanışlı olur.

Parantez içindeki sorunuz için "Ayrıca, bir arabirimi uygulayan bir nesneyi alan bir yöntemi nasıl yazabilirsiniz? Bu mümkün mü?"

public void DoSomethingToAnObject(IInterface whatever) { ... }

Bu doğrudan "belirli bir şey yapan bir nesneyle konuşun" içine takılır. Yukarıda tanımlanan yöntem, nesneden ne bekleyeceğini bilir, IInterface içindeki her şeyi uygular, ancak bunun ne tür bir nesne olduğunu umursamaz, sadece sözleşmeye bağlı olduğunu, yani bir arayüzün ne olduğunu.

Örneğin, muhtemelen hesap makinelerini biliyorsunuzdur ve günlerinizde muhtemelen birkaç tane kullandınız, ancak çoğu zaman hepsi farklıdır. Öte yandan, standart bir hesap makinesinin nasıl çalışması gerektiğini bilirsiniz, böylece her hesap makinesinin diğerinin sahip olmadığı belirli özellikleri kullanamasanız bile hepsini kullanabilirsiniz.

Arayüzlerin güzelliği budur. Belli bir davranış bekleyebileceği nesnelerin kendisine aktarılacağını bilen bir kod parçası yazabilirsiniz. Bir yuvanın ne tür bir nesne olduğunu umursamıyor, sadece gerekli davranışı destekliyor.

Size somut bir örnek vereyim.

Windows formları için özel olarak hazırlanmış bir çeviri sistemimiz var. Bu sistem, bir form üzerindeki denetimler arasında dolaşır ve her birindeki metni çevirir. Sistem, bir Metin özelliğine sahip olan kontrol türü türü ve benzer temel şeyler gibi temel kontrollerin nasıl işleneceğini bilir, ancak temel herhangi bir şey için yetersiz kalır.

Şimdi, kontroller üzerinde kontrolümüz olmayan önceden tanımlanmış sınıflardan miras aldığı için, üç şeyden birini yapabiliriz:

  1. Tercüme sistemimiz için özellikle hangi kontrol tipiyle çalıştığını saptamak ve doğru bitleri (bakım kabusu) tercüme etmek için destek oluşturun
  2. Temel sınıflara destek oluşturun (imkansız, çünkü tüm kontroller önceden tanımlanmış farklı sınıflardan miras alır)
  3. Arayüz desteği ekle

Bu yüzden nr yaptık. 3. Tüm kontrollerimiz, bize bir yöntem, "kendini" bir çeviri metni / kuralları konteynerine çevirme yeteneği sağlayan bir arayüz olan ILocalizable'ı uygular. Bu nedenle, formun ne tür bir kontrol bulduğunu bilmesine gerek yoktur, sadece belirli arayüzü uygular ve kontrolü yerelleştirmek için çağırabileceği bir yöntem olduğunu bilir.


31
IoC'den neden en başta bahsettik, çünkü bu sadece daha fazla karışıklık yaratacaktır.
Kevin Le - Khnle

1
Katılıyorum, arayüzlere karşı programlamanın sadece IoC'yi daha kolay ve güvenilir hale getirmek için bir teknik olduğunu söyleyebilirim.
terjetyl

28

Arabirim Kodu Kodlama Uygulamanın Java veya Arabirim yapısı ile ilgisi yoktur.

Bu kavram, Patterns / Gang of Four kitaplarında ön plana çıkarıldı, ancak büyük olasılıkla bundan önce de vardı. Kavram kesinlikle Java'nın varlığından çok önce vardı.

Java Arayüzü yapısı, bu fikre (diğer şeylerin yanı sıra) yardımcı olmak için oluşturuldu ve insanlar, orijinal niyetten ziyade anlamın merkezi olarak yapıya çok fazla odaklandı. Ancak, Java, C ++, C #, vb.Genel ve özel yöntemlere ve niteliklere sahip olmamızın nedeni budur.

Bu sadece bir nesnenin veya sistemin genel arayüzüyle etkileşim anlamına gelir. Endişelenmeyin, hatta dahili olarak ne yaptığını tahmin etmeyin. Nasıl uygulandığı konusunda endişelenmeyin. Nesneye yönelik kodda, kamuya açık yöntemlerle özel yöntem / özniteliklere sahip olmamızın nedeni budur. Herkese açık yöntemleri kullanmamız amaçlanmıştır, çünkü özel yöntemler sadece dahili olarak, sınıf içinde kullanım içindir. Sınıfın uygulanmasını oluştururlar ve genel arayüz değiştirilmeden gerektiği gibi değiştirilebilirler. İşlevsellikle ilgili olarak, bir sınıftaki bir yöntemin, aynı parametrelerle her çağırışınızda aynı işlemi beklenen sonuçla gerçekleştireceğini varsayalım. Yazarın, insanların onunla etkileşimini bozmadan sınıfın çalışma şeklini, uygulamasını değiştirmesini sağlar.

Ve hiç bir Interface yapısı kullanmadan uygulamaya değil, arayüze programlayabilirsiniz. Arabirim yapısı olmayan C ++ uygulamasına değil arabirime programlayabilirsiniz. Sistemlerin içindeki nesneler üzerinde yöntem çağırmak yerine, genel arabirimler (sözleşmeler) aracılığıyla etkileşim kurdukları sürece, iki büyük kurumsal sistemi çok daha sağlam bir şekilde entegre edebilirsiniz. Arabirimlerin aynı giriş parametreleri göz önüne alındığında her zaman aynı beklenen şekilde tepki vermesi beklenir; arayüze uygulanmışsa, uygulamaya değil. Konsept birçok yerde çalışır.

Java Arayüzleri'nin 'Uygulamaya Değil, Arayüze Program' kavramı ile ne yapacak kadar çok şey olduğu düşüncesini sallayın. Kavramın uygulanmasına yardımcı olabilirler, ancak kavram değildirler .


1
İlk cümle her şeyi söylüyor. Bu kabul edilen cevap olmalı.
madumlao

14

Arayüzlerin nasıl çalıştığını anladığınız anlaşılıyor, ancak bunları ne zaman kullanacağınızdan ve sundukları avantajlardan emin değilsiniz. Bir arayüzün ne zaman anlamlı olacağına dair birkaç örnek:

// if I want to add search capabilities to my application and support multiple search
// engines such as Google, Yahoo, Live, etc.

interface ISearchProvider
{
    string Search(string keywords);
}

GoogleSearchProvider, YahooSearchProvider, LiveSearchProvider vb. oluşturabilirim.

// if I want to support multiple downloads using different protocols
// HTTP, HTTPS, FTP, FTPS, etc.
interface IUrlDownload
{
    void Download(string url)
}

// how about an image loader for different kinds of images JPG, GIF, PNG, etc.
interface IImageLoader
{
    Bitmap LoadImage(string filename)
}

ardından JpegImageLoader, GifImageLoader, PngImageLoader vb.

Çoğu eklenti ve eklenti sistemi arabirimler üzerinden çalışır.

Bir başka popüler kullanım, Depo deseni içindir. Farklı kaynaklardan bir posta kodu listesi yüklemek istediğimi varsayalım

interface IZipCodeRepository
{
    IList<ZipCode> GetZipCodes(string state);
}

daha sonra bir XMLZipCodeRepository, SQLZipCodeRepository, CSVZipCodeRepository, vb. Veritabanı hazır olduğunda, XML sürümünü değiştirmek için bir SQLRepository yazıyorum. Kodumun geri kalanı değişmeden kalır, çünkü yalnızca arabirimlerden çalışır.

Yöntemler aşağıdaki gibi arayüzleri kabul edebilir:

PrintZipCodes(IZipCodeRepository zipCodeRepository, string state)
{
    foreach (ZipCode zipCode in zipCodeRepository.GetZipCodes(state))
    {
        Console.WriteLine(zipCode.ToString());
    }
}

10

Benzer sınıflar kümeniz olduğunda kodunuzu çok daha genişletilebilir ve bakımı daha kolay hale getirir. Ben küçük bir programcıyım, bu yüzden uzman değilim, ama benzer bir şey gerektiren bir projeyi yeni bitirdim.

Tıbbi cihaz çalıştıran bir sunucuyla konuşan istemci tarafı yazılım üzerinde çalışıyorum. Bu cihazın, müşterinin zaman zaman yapılandırması gereken bazı yeni bileşenlere sahip yeni bir sürümünü geliştiriyoruz. İki tür yeni bileşen vardır ve bunlar farklıdır, ancak çok benzerler. Temel olarak, iki yapılandırma formu, iki liste sınıfı, her şeyden ikisi oluşturmak zorunda kaldım.

Gerçek mantığın neredeyse tamamını tutacak her bir kontrol türü için soyut bir temel sınıf oluşturmanın en iyi olacağına karar verdim ve daha sonra iki bileşen arasındaki farkları ele almak için türler türettik. Ancak, temel sınıflar her zaman türleri hakkında endişelenmem gerekirse bu bileşenler üzerinde işlem yapamazdı (iyi olabilirdi, ancak her yöntemde bir "if" deyimi veya anahtarı olurdu) .

Bu bileşenler için basit bir arayüz tanımladım ve tüm temel sınıflar bu arayüzle konuşuyor. Şimdi bir şeyi değiştirdiğimde, hemen hemen her yerde 'sadece çalışıyor' ve kod çoğaltmam yok.


10

Orada bir sürü açıklama var, ama daha da basitleştirmek için. Örneğin a List. Aşağıdaki gibi bir liste uygulanabilir:

  1. Dahili bir dizi
  2. Bağlantılı liste
  3. Diğer uygulamalar

Bir arayüz oluşturarak, a List. Yalnızca List'in tanımını veya Listgerçekte ne anlama geldiğini kodlarsınız.

Herhangi bir tür uygulamayı dahili olarak bir arrayuygulama olarak kullanabilirsiniz. Ancak, bir nedenden dolayı uygulamayı bir hata veya performans demek istediğinizi varsayalım. Sonra sadece beyanı değiştirmek zorunda List<String> ls = new ArrayList<String>()için List<String> ls = new LinkedList<String>().

Kodun başka hiçbir yerinde, başka bir şeyi değiştirmeniz gerekmeyecek; Çünkü her şey tanımı üzerine inşa edilmiştir List.


8

Java'da program yaparsanız JDBC buna iyi bir örnektir. JDBC bir dizi arabirim tanımlar ancak uygulama hakkında hiçbir şey söylemez. Uygulamalarınız bu arabirim kümesine karşı yazılabilir. Teorik olarak, bazı JDBC sürücüsünü seçersiniz ve uygulamanız işe yarayabilir. Daha hızlı veya "daha iyi" veya daha ucuz bir JDBC sürücüsü olduğunu fark ederseniz veya herhangi bir nedenle, teorik olarak özellik dosyanızı yeniden yapılandırabilirsiniz ve uygulamanızda herhangi bir değişiklik yapmak zorunda kalmadan uygulamanız yine de çalışır.


Daha iyi bir sürücünün kullanılabilir olması durumunda kullanışlı değildir, veritabanı satıcılarını tamamen değiştirmeyi mümkün kılar.
Ken Liu

3
JDBC o kadar kötü ki değiştirilmesi gerekiyor. Başka bir örnek bulun.
Joshua

JDBC kötüdür, ancak herhangi bir nedenle arabirim ile uygulama veya soyutlama düzeyleriyle ilgili değildir. Ve böylece söz konusu kavramı göstermek için, sadece mükemmel.
Erwin Smout

8

Arayüzlere programlama harika, gevşek bağlantıyı teşvik ediyor. @Lassevk'in de belirttiği gibi Inversion of Control bunu büyük ölçüde kullanıyor.

Ayrıca, SOLID ilkelerine bakın . işte bir video serisi

Sabit kodlanmış (güçlü bir şekilde birleştirilmiş örnek) geçer, daha sonra arayüzlere bakar ve sonunda bir IoC / DI aracına ilerler (NInject)


7

Bu soruya geç gelen biriyim, ancak burada "Bir uygulamaya değil, bir arayüze program" satırının GoF (Dörtlü Çete) Tasarım Desenleri kitabında iyi bir tartışma yaşadığını belirtmek istiyorum.

Bu, s. 18:

Bir uygulamaya değil, bir arayüze programlayın

Değişkenleri belirli somut sınıfların örnekleri olarak ilan etmeyin. Bunun yerine, yalnızca soyut bir sınıf tarafından tanımlanan bir arabirime bağlı kalın. Bunu, bu kitaptaki tasarım modellerinin ortak bir teması olarak bulacaksınız.

ve bunun üstünde, şununla başladı:

Nesneleri yalnızca soyut sınıflar tarafından tanımlanan arayüz açısından manipüle etmenin iki faydası vardır:

  1. Nesneler, istemcilerin beklediği arabirime bağlı kaldığı sürece, istemciler kullandıkları belirli nesne türlerinden habersiz kalırlar.
  2. İstemciler bu nesneleri uygulayan sınıflardan habersiz kalırlar. Müşteriler sadece arayüzü tanımlayan soyut sınıf (lar) ı bilirler.

Yani başka bir deyişle, sınıflarınızı quack()ördekler için bir yöntem ve sonra bark()köpekler için bir yöntem olacak şekilde yazmayın , çünkü bunlar bir sınıfın (veya alt sınıfın) belirli bir uygulaması için çok spesifiktir. Bunun yerine, örneğin genel yeterince temel sınıfta kullanılacak olan isimler kullanılarak yöntem yazmak giveSound()veya move()onlar ördekler, köpekler, hatta otomobiller için kullanılabilir ve sonra sınıfları istemci sadece söylemek, böylece .giveSound()ziyade nesneye gönderilecek doğru mesajı vermeden önce türün kullanılıp kullanılmayacağını quack()veya bark()hatta tipinin belirlenmesini düşünmek.


6

Önceden seçilmiş cevaba (ve burada çeşitli bilgilendirici yayınlara) ek olarak, Baş İlk Tasarım Desenlerinin bir kopyasını almanızı şiddetle tavsiye ederim . Çok kolay okunur ve sorunuzu doğrudan yanıtlar, neden önemli olduğunu açıklar ve size bu prensibi (ve diğerlerini) kullanmak için kullanabileceğiniz birçok programlama modeli gösterir.


5

Mevcut yayınlara eklemek için bazen arayüzlere kodlama yapmak, geliştiriciler aynı anda ayrı bileşenler üzerinde çalışırken büyük projelere yardımcı olur. İhtiyacınız olan tek şey arayüzleri tanımlamak ve bunlara kod yazmak, diğer geliştiriciler ise uyguladığınız arayüze kod yazmaktır.


4

Birim Testi için de iyidir, kendi sınıflarınızı (arayüzün gereksinimlerini karşılayan) ona bağlı bir sınıfa enjekte edebilirsiniz.


4

Soyutlamalara bağlı olmasak bile arabirimlere programlamak avantajlı olabilir.

Arayüzlere programlama bizi bir nesnenin içeriğe uygun alt kümesini kullanmaya zorlar . Bu yardımcı olur çünkü:

  1. bağlamsal olarak uygunsuz şeyler yapmamızı engeller ve
  2. gelecekte uygulamayı güvenli bir şekilde değiştirmemize izin verir.

Örneğin Person, Friendve Employeearabirimini uygulayan bir sınıfı düşünün .

class Person implements AbstractEmployee, AbstractFriend {
}

Kişinin doğum günü bağlamında Friend, bir kişiye gibi davranılmasını önlemek için arayüze programlıyoruz Employee.

function party() {
    const friend: Friend = new Person("Kathryn");
    friend.HaveFun();
}

Kişinin çalışması bağlamında, Employeeişyeri sınırlarının bulanıklaşmasını önlemek için arayüze program yapıyoruz .

function workplace() {
    const employee: Employee = new Person("Kathryn");
    employee.DoWork();
}

Harika. Farklı bağlamlarda uygun şekilde davrandık ve yazılımımız iyi çalışıyor.

Gelecekte, işimiz köpeklerle çalışmak için değişirse, yazılımı oldukça kolay bir şekilde değiştirebiliriz. İlk olarak, Doghem Friendve hem de uygulayan bir sınıf oluştururuz Employee. Sonra güvenle değiştirmek new Person()için new Dog(). Her iki işlevin de binlerce satır satırı olsa bile, aşağıdakilerin doğru olduğunu bildiğimiz için bu basit düzenleme çalışır:

  1. İşlev partyyalnızca Friendöğesinin alt kümesini kullanır Person.
  2. İşlev workplaceyalnızca Employeeöğesinin alt kümesini kullanır Person.
  3. Sınıf Doguygular hem Friendve Employeearayüzler.

Öte yandan, ya programlanmış ya partyda workplaceprogramlanmış Personolsaydı, her ikisinin de Person-özel koda sahip olma riski vardır . Dan değiştirme Personiçin Dogherhangi kökünü kazımak için kod boyunca tarak bizi gerektirecektir Person'e özgü kod Dogdesteklemez.

Ahlaki : arayüzlere programlama, kodumuzun uygun şekilde davranmasına ve değişime hazır olmasına yardımcı olur. Ayrıca, kodumuzu daha da fazla avantaj getiren soyutlamalara bağlı olacak şekilde hazırlar.


1
Aşırı geniş arayüzlere sahip olmadığınızı varsayarsak, yani.
Casey

4

Eğer Swimmerişlevsellik eklemek için yeni bir sınıf yazıyorum ve sınıf swim()bir nesne kullanmanız gerekiyorsa Dogve bu Dogsınıf Animalbildiren arabirimi uygular swim().

Hiyerarşinin ( Animal) üstünde çok soyut, altta ( Dog) ise çok somut. "Arayüzlere programlama" hakkında düşündüğüm yol, Swimmersınıf yazarken , kodumu bu durumda bir hiyerarşiye kadar olan arayüze yazmak istiyorum.Animal nesne . Bir arayüz uygulama detaylarından muaftır ve bu nedenle kodunuzu gevşek bir şekilde bağlar.

Uygulama ayrıntıları zamanla değiştirilebilir, ancak etkileşimde bulunduğunuz tüm uygulama değil arayüz ile olduğundan kalan kodu etkilemez. Uygulamanın nasıl olduğunu umursamıyorsunuz ... tek bildiğiniz şey, arayüzü uygulayacak bir sınıf olacak.


3

Yani, sadece bunu doğru yapmak için, bir arayüzün avantajı, bir yöntemin çağrılmasını herhangi bir sınıftan ayırabilmemdir. Bunun yerine, uygulamanın hangi sınıfı seçtiğim sınıftan verildiği bir arabirim örneği oluşturmak, arabirimi uygular. Böylece benzer ama biraz farklı işlevselliklere sahip olan ve bazı durumlarda (arayüzün niyeti ile ilgili durumlar) birçok nesneye sahip olmamı sağlar.

Örneğin, bir hareket arayüzüm olabilir. Bir şeyi 'hareket ettiren' bir yöntem ve hareket arabirimini uygulayan herhangi bir nesne (Kişi, Araba, Kedi) aktarılabilir ve hareket ettirilmesi söylenebilir. Yöntem olmadan her biri sınıfın türünü bilir.


3

Eklentilerle genişletilebilen 'Zebra' adlı bir ürününüz olduğunu düşünün. Bazı dizindeki DLL'leri arayarak eklentileri bulur. Tüm bu DLL'leri yükler ve uygulayan herhangi bir sınıf bulmak için yansıma kullanır IZebraPluginve sonra eklentileri ile iletişim kurmak için bu arabirim yöntemlerini çağırır.

Bu, onu herhangi bir eklenti sınıfından tamamen bağımsız hale getirir - sınıfların ne olduğu umurumda değil. Sadece arayüz özelliklerini yerine getirmeleri önemlidir.

Arayüzler, bu gibi genişletilebilirlik noktalarını tanımlamanın bir yoludur. Bir arabirimle konuşan kod daha gevşek bir şekilde birleştirilmiştir - aslında başka hiçbir özel kodla birleştirilmez. Orijinal geliştiriciyle hiç tanışmayan insanlar tarafından yıllar sonra yazılan eklentilerle etkileşime girebilir.

Bunun yerine sanal işlevlere sahip bir temel sınıf kullanabilirsiniz - tüm eklentiler temel sınıftan türetilir. Ancak bu çok daha sınırlayıcıdır çünkü bir sınıfın yalnızca bir temel sınıfı olabilirken, herhangi bir sayıda arabirimi uygulayabilir.


3

C ++ açıklaması.

Bir arayüzü sınıfların genel yöntemleri olarak düşünün.

Daha sonra, kendi işlevini yerine getirmek için bu genel yöntemlere 'bağımlı' bir şablon oluşturabilirsiniz (sınıflar genel arabiriminde tanımlanan işlev çağrılarını yapar). Bu şablonun Vector sınıfı gibi bir kap olduğunu ve bağlı olduğu arayüzün bir arama algoritması olduğunu varsayalım.

Vector'un çağrı yaptığı işlevleri / arabirimi tanımlayan herhangi bir algoritma sınıfı, (orijinal yanıtta açıklandığı gibi) 'sözleşmeyi' karşılayacaktır. Algoritmaların aynı temel sınıfta olması bile gerekmez; tek gereksinim Vector'in bağlı olduğu işlevlerin / yöntemlerin algoritmanızda tanımlanmasıdır.

Tüm bunların amacı, Vector'in bağlı olduğu arayüzü (kabarcık arama, sıralı arama, hızlı arama) sağladığı sürece herhangi bir farklı arama algoritması / sınıfı sağlayabilmenizdir.

Ayrıca, Arama algoritmalarınızın bağlı olduğu arabirimi / sözleşmeyi yerine getirmelerini sağlayarak Vector ile aynı arama algoritmasını kullanan diğer kapsayıcıları (listeler, kuyruklar) tasarlamak da isteyebilirsiniz.

Bu, zamandan tasarruf sağlar (OOP prensibi 'kodun yeniden kullanılması'), aşırı büyümüş bir miras ağacıyla ilgili sorunu aşırı karmaşıklaştırmadan oluşturduğunuz her yeni nesneye tekrar tekrar yerine bir algoritma yazabildiğiniz için zaman kazandırır.

İşlerin nasıl işlediğini 'kaçırmak'; Standart TEMPLATE Kütüphanesi çerçevesinin çoğu bu şekilde çalıştığı için büyük zaman (en azından C ++ 'da).

Elbette kalıtım ve soyut sınıfları kullanırken bir arayüze programlama metodolojisi değişir; ancak prensip aynıdır, genel işlevleriniz / yöntemleriniz sınıf arayüzünüzdür.

Bu çok büyük bir konu ve Tasarım Desenlerinin temel taşlarından biri.


3

Java'da bu somut sınıfların tümü CharSequence arabirimini uygular:

CharBuffer, String, StringBuffer, StringBuilder

Bu somut sınıfların Nesne dışında ortak bir ana sınıfı yoktur, bu nedenle, her biri karakter dizileriyle, temsil eden veya manipüle eden bir dizi şeyle ilgili olmasından başka, onları ilgilendiren hiçbir şey yoktur. Örneğin, String nesnesi başlatıldıktan sonra String karakterleri değiştirilemezken, StringBuffer veya StringBuilder karakterleri düzenlenebilir.

Yine de bu sınıfların her biri, CharSequence arayüz yöntemlerini uygun bir şekilde uygulayabilir:

char charAt(int index)
int length()
CharSequence subSequence(int start, int end)
String toString()

Bazı durumlarda, String'i kabul etmek için kullanılan Java sınıfı kitaplığı sınıfları artık CharSequence arabirimini kabul edecek şekilde revize edilmiştir. Bu nedenle, StringBuilder örneğiniz varsa, bir String nesnesini çıkarmak yerine (yeni bir nesne örneğini başlatmak anlamına gelir), bunun yerine CharSequence arabirimini uygularken StringBuilder'ın kendisini iletebilir.

Bazı sınıfların uyguladığı Appendable arabirimi, karakterlerin temeldeki somut sınıf nesnesi örneğinin bir örneğine eklenebileceği her durum için aynı faydaya sahiptir. Bu somut sınıfların tümü Appendable arabirimini uygular:

BufferedWriter, CharArrayWriter, CharBuffer, FileWriter, FilterWriter, LogStream, OutputStreamWriter, PipedWriter, PrintStream, PrintWriter, StringBuffer, StringBuilder, StringWriter, Yazar


CharSequenceAnemik gibi çok kötü arayüzler . Keşke Java ve .NET, arayüzlerin varsayılan uygulamaya sahip olmasına izin vermişti, böylece insanlar sadece kazan plakası kodunu en aza indirgemek amacıyla arayüzleri azaltmayacaktı. Herhangi bir yasal CharSequenceuygulama göz önüne alındığında , Stringsadece yukarıdaki dört yöntemi kullanma işlevlerinin çoğunu taklit edebilir , ancak birçok uygulama bu işlevleri başka şekillerde çok daha verimli bir şekilde gerçekleştirebilir. Ne yazık ki, belirli bir uygulama bile CharSequenceher şeyi tek bir tutar char[]ve birçok performans olabilir ...
supercat

... indexOfhızlıca yapılan işlemler gibi , belirli bir uygulamaya aşina olmayan bir arayanın, her bir karakteri incelemek CharSequenceiçin kullanmak yerine bunu yapmasını istemesinin bir yolu yoktur charAt.
supercat

3

Kısa öykü: Bir postacıdan eve gittikten sonra teslim edilecek adresin bulunduğu kapakları (mektuplar, belgeler, çekler, hediye kartları, başvuru, aşk mektubu) almaları istenir.

Kapak olmadığını varsayalım ve postacıdan evden sonra eve gitmesini ve her şeyi almasını ve diğer insanlara teslim etmesini isteyin, postacı kafası karışabilir.

Öyleyse kapakla daha iyi sarın (hikayemizde arayüz) o zaman işini iyi yapacak.

Şimdi postacının işi sadece kapakları almak ve teslim etmektir (kapakta ne olduğunu rahatsız etmez).

Bir tür oluşturun interfaceGerçek olmayan , ancak gerçek türle uygulayın.

Arabirime oluşturmak, bileşenlerinizin kodun geri kalanına kolayca sığması anlamına gelir

Size bir örnek vereyim.

aşağıdaki gibi AirPlane arayüzüne sahipsiniz.

interface Airplane{
    parkPlane();
    servicePlane();
}

Denetleyici sınıfınızdaki gibi uçaklarınız olduğunu varsayalım

parkPlane(Airplane plane)

ve

servicePlane(Airplane plane)

programınızda uygulanmaktadır. Kodunuzu KIRMAK olmayacak . Yani, argümanları kabul ettiği sürece değişmeme gerek yokAirPlane .

Gerçek tip rağmen herhangi Airplane kabul edeceğinden, flyer, highflyr,fighter , vb

Ayrıca, bir koleksiyonda:

List<Airplane> plane; // Tüm uçaklarınızı alacak.

Aşağıdaki örnek anlayışınızı netleştirecektir.


Onu uygulayan bir savaş uçağınız var, yani

public class Fighter implements Airplane {

    public void  parkPlane(){
        // Specific implementations for fighter plane to park
    }
    public void  servicePlane(){
        // Specific implementatoins for fighter plane to service.
    }
}

HighFlyer ve diğer clasess için aynı şey:

public class HighFlyer implements Airplane {

    public void  parkPlane(){
        // Specific implementations for HighFlyer plane to park
    }

    public void  servicePlane(){
        // specific implementatoins for HighFlyer plane to service.
    }
}

Şimdi denetleyicinizin AirPlanebirkaç kez kullanarak sınıflarını düşünün ,

Controller sınıfınızın aşağıdaki gibi ControlPlane olduğunu varsayalım,

public Class ControlPlane{ 
 AirPlane plane;
 // so much method with AirPlane reference are used here...
}

İşte yeni AirPlanetip örneklerinizi istediğiniz kadar yapabilirsiniz ve ControlPlanesınıf kodunu değiştirmediğiniz gibi sihir gelir .

Bir örnek ekleyebilirsiniz ...

JumboJetPlane // implementing AirPlane interface.
AirBus        // implementing AirPlane interface.

Önceden oluşturulan türlerin örneklerini de kaldırabilirsiniz.


2

Bir arabirim, uygulama sınıfınızın sözleşmede (arabirim) yazılmış yöntemleri uygulamasını istediğiniz bir sözleşme gibidir. Java çoklu miras sağlamadığından, "arayüze programlama" çoklu miras elde etmenin iyi bir yoludur.

Zaten başka bir B sınıfını genişleten A sınıfınız varsa, ancak A sınıfının da belirli yönergeleri izlemesini veya belirli bir sözleşmeyi uygulamasını istiyorsanız, bunu "arabirime programlama" stratejisiyle yapabilirsiniz.


2

S: - ... "Bir arabirim uygulayan herhangi bir sınıfı kullanabilir misiniz?"
C: - Evet.

S: - ... "Bunu ne zaman yapmanız gerekir?"
C: - Arabirimleri uygulayan bir sınıfa ihtiyacınız olduğunda.

Not: Bir sınıf tarafından uygulanmayan bir arabirimi başlatamadık - Doğru.

  • Neden?
  • Arayüz sadece metot prototiplerine sahip olduğundan tanımları değil (sadece fonksiyon isimleri, mantıklarını değil)

AnIntf anInst = new Aclass();
// bunu yapabileceğini yalnızca Aclass uygular AnIntf.
// anInst'in Aclass referansı olacak.


Not: Artık Bclass ve Cclass aynı Dintf'i uygularsa ne olduğunu anlayabiliriz.

Dintf bInst = new Bclass();  
// now we could call all Dintf functions implemented (defined) in Bclass.

Dintf cInst = new Cclass();  
// now we could call all Dintf functions implemented (defined) in Cclass.

Neyimiz var: Aynı arabirim prototipleri (arabirimdeki işlev adları) ve farklı uygulamaları çağırır.

Kaynakça: Prototipler - wikipedia


1

Program bir arayüze arayüz tarafından tanımlanan sözleşmenin uygulanmasını sorunsuz bir şekilde değiştirmenizi sağlar. Sözleşme ve belirli uygulamalar arasında gevşek bağlantıya izin verir.

IInterface classRef = new ObjectWhatever()

IInterface uygulayan herhangi bir sınıf kullanabilirsiniz? Ne zaman yapman gerekir?

İyi örnek için bu SE sorusuna bir göz atın.

Java sınıfı arabirimi neden tercih edilmeli?

bir Arayüz kullanmak performansı vurur?

eğer öyleyse ne kadar?

Evet. Saniyeler içinde hafif bir performans yükü olacak. Ancak uygulamanızın arayüzün uygulamasını dinamik olarak değiştirme gereksinimi varsa, performans etkisi konusunda endişelenmeyin.

iki kod parçasını korumak zorunda kalmadan nasıl önleyebilirsiniz?

Uygulamanızın bunlara ihtiyacı varsa, birden çok arabirim uygulamasından kaçınmaya çalışmayın. Arayüzün belirli bir uygulama ile sıkı bir şekilde eşleşmemesi durumunda, bir uygulamayı başka bir uygulamaya değiştirmek için yamayı dağıtmanız gerekebilir.

İyi bir kullanım örneği: Strateji modelinin uygulanması:

Strateji Modelinin Gerçek Dünya Örneği


1

bir arayüze program GOF kitabından bir terimdir. doğrudan java arayüzü ile değil, gerçek arayüzler ile ilgili olduğunu söylemek olmaz. temiz katman ayrımı sağlamak için, sistemler arasında bazı ayrımlar oluşturmanız gerekir: Örneğin, kullanmak istediğiniz somut bir veritabanınız olduğunu, asla "veritabanına programlayamazsınız", bunun yerine "depolama arayüzüne program yaparsınız" diyelim. Aynı şekilde asla "bir Web Hizmetine programlama" yapmazsınız, bunun yerine "istemci arayüzüne" programlama yaparsınız. bu, şeyleri kolayca değiştirebilmeniz için.

bu kuralları bana yardımcı buluyorum:

1 . birden çok nesne türümüz olduğunda java arayüzü kullanırız. eğer tek bir cisim varsa, noktayı göremiyorum. bir fikrin en az iki somut uygulaması varsa, bir java arayüzü kullanırdım.

2 . Yukarıda belirtildiği gibi, harici bir sistemden (depolama sistemi) kendi sisteminize (yerel DB) ayrıştırmayı getirmek istiyorsanız, aynı zamanda bir arayüz kullanın.

bunları ne zaman kullanacağınızı düşünmenin iki yolu olduğuna dikkat edin. Bu yardımcı olur umarım.


0

Ayrıca burada çok iyi ve açıklayıcı cevaplar görüyorum, bu yüzden bu yöntemi kullanırken fark ettiğim bazı ekstra bilgiler de dahil olmak üzere burada bakış açımı vermek istiyorum.

Birim testi

Son iki yıldır bir hobi projesi yazdım ve bunun için birim testleri yazmadım. Yaklaşık 50K satır yazdıktan sonra, birim testleri yazmanın gerçekten gerekli olacağını öğrendim. Arabirimler kullanmadım (ya da çok az) ... ve ilk ünite testimi yaptığımda, karmaşık olduğunu öğrendim. Neden?

Çünkü sınıf değişkenleri ve / veya parametreler olarak girdi için kullanılan birçok sınıf örneği yapmak zorunda kaldım. Bu yüzden testler daha çok entegrasyon testlerine benziyor (hepsi birbirine bağlı olduğundan sınıfların tam bir 'çerçevesini' yapmak zorunda).

Arayüz korkusu Arayüz kullanmaya karar verdim. Korkum, tüm işlevselliği her yerde (kullanılan tüm sınıflarda) birden çok kez uygulamak zorunda olduğumdu. Bir şekilde bu doğrudur, ancak kalıtım kullanarak çok azaltılabilir.

Arayüzlerin kombinasyonu ve kalıtım I kombinasyonunun kullanılmasının çok iyi olduğunu öğrendim. Çok basit bir örnek veriyorum.

public interface IPricable
{
    int Price { get; }
}

public interface ICar : IPricable

public abstract class Article
{
    public int Price { get { return ... } }
}

public class Car : Article, ICar
{
    // Price does not need to be defined here
}

Bu şekilde, bir arabanın arayüz (ICar) olarak kullanılması avantajına sahip olmakla birlikte, kod kopyalamak gerekli değildir.


0

Önce bazı tanımlarla başlayalım:

Arayüz n. Bir nesnenin işlemleri tarafından tanımlanan tüm imza kümesine nesneye arabirim denir

Tip n. Belirli bir arayüz

Bir basit bir örnek arayüzü yukarıda tanımlandığı gibi tüm PDO nesne yöntemleri olabilir query(), commit(),close() bir bütün olarak, ayrı ayrı değil, vb. Bu yöntemler, yani arabirimi, nesneye gönderilebilen tüm ileti kümesini, istekleri tanımlar.

Bir tip , yukarıda tarif edildiği gibi belirli bir arabirimdir. Ben göstermek için uydurma şekil arayüzünü kullanacağız: draw(), getArea(), getPerimeter()vb ..

Bir nesne Veritabanı türde ise bunu mesajları / veritabanı arayüzü isteklerini kabul ettiği anlamına, query(), commit()vb .. Nesneler birçok türde olabilir. Bir veritabanı nesnesinin arabirimini uyguladığı sürece şekil türünde olmasını sağlayabilirsiniz, bu durumda bu alt-yazım olur .

Birçok nesne birçok farklı arabirim / tipte olabilir ve bu arabirimi farklı şekilde uygulayabilir. Bu, nesneleri kullanmamıza izin verir, hangisini kullanacağımızı seçmemize izin verir. Polimorfizm olarak da bilinir.

İstemci, uygulamanın değil, yalnızca arayüzün farkında olacaktır.

Yani bir arayüze özü programlamada gibi soyut sınıfın çeşit yapım yer alacağı Shapesadece yani belirtilen arayüz ile draw(), getCoordinates(), getArea()vb .. Ve sonra farklı beton sınıfları böyle bir daire sınıfının, Kare sınıf, Üçgen sınıf olarak bu arabirimleri uygulayan var. Bu nedenle bir arayüze program değil bir uygulama.


0

"Programlama arayüzü", sabit kodu tam olarak sağlamaz, yani kodunuzun önceki işlevselliği bozmadan genişletilmesi anlamına gelir. Yalnızca uzantılar, önceki kodu düzenlemez.

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.