“Bir arayüze programlama” anlamak


29

"Bir uygulama yerine bir arayüze programlama" terimi ile çok karşılaştım ve sanırım ne anlama geldiğini anlıyorum. Ancak bunun faydalarını ve olası uygulamalarını anladığımdan emin olmak istiyorum.

"Arayüze programlama", mümkün olduğunda, somut bir uygulamaya atıfta bulunmak yerine, daha soyut bir sınıf seviyesine (bir arayüz, soyut sınıf veya bazen bir tür üst sınıf) atıfta bulunulması gerektiği anlamına gelir.

Java'da yaygın bir örnek kullanmaktır:

List myList = new ArrayList();yerine ArrayList myList = new ArrayList();.

Bununla ilgili iki sorum var:

  1. Bu yaklaşımın temel faydalarını anladığımdan emin olmak istiyorum. Faydaların çoğunlukla esneklik olduğunu düşünüyorum. Bir nesneyi somut bir uygulamadan ziyade daha yüksek bir referans olarak ilan etmek, geliştirme döngüsü boyunca ve kod boyunca daha fazla esneklik ve sürdürülebilirlik sağlar. Bu doğru mu? Esneklik ana yararı mı?

  2. 'Bir arabirime programlama' için daha fazla yol var mı? Yoksa "somut bir uygulamadan ziyade bir arayüz olarak bir değişken ilan etmek" bu konseptin tek uygulaması mıdır?

Ben ediyorum Java yapı Arayüz bahsetmiyoruz . OO prensibinden "bir arayüze değil bir uygulamaya programlama" dan bahsediyorum. Bu prensipte dünya "arayüzü", bir sınıfın herhangi bir " süper tipine" ( bir arayüze, soyut bir sınıfa veya daha somut alt sınıflara göre daha soyut ve daha az somut olan basit bir üst sınıfa) karşılık gelir.




1
Bu cevap size kolay anlaşılır bir örnek sunar. Programmers.stackexchange.com/a/314084/61852
Tulains Córdova

Yanıtlar:


44

"Arayüze programlama", mümkün olduğunda, somut bir uygulamaya atıfta bulunmak yerine, daha soyut bir sınıf seviyesine (bir arayüz, soyut sınıf veya bazen bir tür üst sınıf) atıfta bulunulması gerektiği anlamına gelir.

Bu doğru değil . Ya da en azından, tamamen doğru değil.

Daha önemli olan nokta, program tasarım perspektifinden geliyor. Burada, üzerinde tasarım odaklama aracının "bir arayüze programlama" Ne değil, kod yapıyor nasıl bunu yapar. Bu, tasarımınızı doğruluk ve esnekliğe doğru iten hayati bir ayrımdır.

Ana fikir, alan adlarının yazılımdan çok daha yavaş değiştiğidir. Bakkal listenizi takip etmek için bir yazılımınız olduğunu söyleyin. 80'lerde bu yazılım bir komut satırına ve disketteki bazı düz dosyalara karşı çalışır. O zaman bir kullanıcı arayüzün var. O zaman listeyi veritabanına yazabilirsin. Daha sonraları buluta ya da cep telefonlarına ya da facebook entegrasyonuna geçebilir.

Kodunuzu özellikle uygulama etrafında tasarladıysanız (disketler ve komut satırları) değişikliklere hazır olmazsınız. Kodunuzu arayüzün etrafında tasarladıysanız (bir alışveriş listesini değiştirmek), uygulamada değişiklik yapmak ücretsizdir.


Cevap için teşekkürler. Yazdıklarına göre, "bir arayüze programlama" nın ne anlama geldiğini ve faydalarının ne olduğunu anladığımı düşünüyorum. Ancak bir sorum var - Bu kavram için en yaygın somut örnek şudur: Bir nesneye referans oluştururken, referans tipini yapmak yerine referans tipini bu nesnenin uyguladığı arabirim türünü (veya bu nesnenin miras aldığı üst sınıfı) yapın nesne türü (Aka, List myList = new ArrayList()yerine ArrayList myList = new ArrayList(). (Soru) sonraki yorumunda ise
Aviv Cohn

Sorum şu: Bana "arabirime programlama" ilkesinin uygulandığı gerçek dünya kodundaki yerler için daha fazla örnek verebilir misiniz? Son yorumda açıklanan ortak örnek dışında?
Aviv Cohn,

6
NO . List/ ArrayListBen hiç bahsettiğim şey değil. EmployeeBir Çalışan kaydını saklamak için kullandığınız bağlantılı tablolardan ziyade, bir nesneyi sağlamak gibidir . Veya şarkılar arasında yineleme yapmak için bir arayüz sağlamak ve bu şarkılar karıştırılmışsa, CD'de veya internetten yayın yapmıyorsa umursamıyor. Onlar sadece bir şarkı dizisi.
Telastyn

“Bir arayüze değil, bir uygulamaya göre programlama” nın Soyutlama OO ilkesini ifade eden bir ilke olduğunu söyler misiniz?
Aviv Cohn,

1
@AvivCohn SpringFramework'a iyi bir örnek olarak öneriyorum. İlkbahardaki her şey, kendi arayüzlerine ve Springs'in ana davranışı olan bir özelliğin beklendiği gibi çalışmaya devam etmesini sağlayarak, kendi uygulamalarına katılarak geliştirilebilir veya özelleştirilebilir ... Veya beklediğiniz gibi özelleştirmeler durumunda. Bir arayüze programlama, entegrasyon çerçevelerini tasarlamak için de en iyi stratejidir . Yine Spring, bahar entegrasyonunu yapıyor. Tasarım zamanında, bir arayüze programlama yapmak UML ile yaptığımız şeydir. Ya da öyle yapardım. Kendimi nasıl yaptığından soyutlayın ve ne yapacağınıza odaklanın .
Laiv

18

"Bir arayüze programlama" anlayışı, soru veya diğer cevapların önerdiğinden farklı. Bu benim anlayışımın doğru olduğunu veya diğer cevaplardakilerin iyi fikirler olmadığını söylemek değildir, sadece o terimi duyduğumda düşündüğüm gibi olmadıkları anlamına gelmez.

Arabirime programlama, bir arabirim (yalnızca bir sınıf kitaplığı, bir dizi işlev, bir ağ protokolü veya başka bir şey olabilir) size sunulduğunda, yalnızca arabirim tarafından garanti edilen şeyleri kullanmaya devam ettiğiniz anlamına gelir. Temel uygulama hakkında bilginiz olabilir (yazmış olabilirsiniz), ancak bu bilgiyi asla kullanmamalısınız.

Örneğin, API'nin size dahili bir şeye "tanıtıcı" olan bazı opak bir değer sunduğunu söyleyin. Bilgin sana bu tutacağın gerçekten bir işaretçi olduğunu söyleyebilir, ve onu reddedebilir ve yapmak istediğin bir işi kolayca yerine getirmeni sağlayacak bir değere erişebilirsin. Ancak arayüz size bu seçeneği sunmuyor; Bunu yapan özel uygulama hakkındaki bilginizdir.

Bununla ilgili sorun, tam olarak arabirimin önleyeceği gibi, kodunuzla uygulama arasında güçlü bir bağlantı oluşturmasıdır. Politikaya bağlı olarak bu, uygulamanın artık değiştirilemeyeceği anlamına gelebilir, çünkü bu kodunuzu kıracak veya kodunuzun çok kırılgan olduğu ve temeldeki uygulamanın her yükseltilmesinden veya değiştirilmesinden kaçınmaya devam edeceği anlamına gelebilir.

Buna büyük bir örnek, Windows için yazılmış programlardır. WinAPI bir arayüzdür, ancak birçok kişi Windows 95’te belirtilen özel bir uygulama nedeniyle işe yarayan numaralar kullandı. Bu numaralar programlarını daha hızlı hale getirdiler ya da başka şeyler gerekenden daha az kodda iş yapmalarına izin verdiler. Ancak bu püf noktaları, programın Windows 2000'de çökeceği anlamına geliyordu çünkü API orada farklı şekilde uygulandı. Program yeterince önemliyse, Microsoft gerçekten devam edebilir ve programın çalışmaya devam etmesi için uygulamaya bazı kesmeler ekleyebilir, ancak bunun maliyeti Windows kodunun karmaşıklığı (tüm sonraki sorunlar ile birlikte) artar. Aynı zamanda Şarap insanları için hayatı daha da zorlaştırıyor, çünkü WinAPI'yi de uygulamaya çalışıyorlar, ancak bunun nasıl yapılacağına dair belgelere başvurabiliyorlar,


Bu iyi bir nokta ve bunu belli bağlamlarda çok duyuyorum.
Telastyn

Senin değinmek istediğin noktayı anlıyorum. Öyleyse, genel programlamaya ne söyleyebileceğinizi adapte edip edemediğimi göreyim: Diyelim ki soyut B sınıfının işlevselliğini kullanan bir sınıf (A sınıfı) var. B ve D Sınıfları miras alır - bunun için somut bir uygulama sağlarlar. sınıfın yaptığı söyleniyor. A sınıfı doğrudan C veya D sınıfını kullanıyorsa, 'esnek bir çözüm olmayan' bir uygulamaya programlama 'denir. Ancak eğer A sınıfı, daha sonra C uygulamasına veya D uygulamasına ayarlanabilecek B sınıfına bir referans kullanıyorsa, işleri daha esnek ve sürdürülebilir hale getirir. Bu doğru mu?
Aviv Cohn,

Eğer bu doğruysa, sorum şu: - 'Bir beton sınıfı referansından ziyade bir arayüz referansı kullanmak' dışında 'bir arayüze programlama' için daha somut örnekler var mı?
Aviv Cohn,

2
@AvivCohn Bu cevapta biraz geç, ancak somut bir örnek dünya çapında ağ. Tarayıcı savaşları sırasında (IE 4 dönemi) web siteleri herhangi bir spesifikasyonun söylediğine değil, bazı tarayıcıların tuhaflıklarına (Netscape veya IE) yazılmıştır. Bu temelde arayüz yerine uygulamaya programlama yapıyordu.
Sebastian Redl

9

Bana kişisel olarak da hiçbir zaman resmi olarak öğretilmediği için kişisel deneyimim hakkında konuşabiliyorum.

İlk amacın doğru. Elde edilen esneklik, yanlışlıkla başlatılmaması gereken somut sınıfın uygulama detaylarını yanlışlıkla çağırmamaktan kaynaklanıyor.

Örneğin ILogger, şu anda somut bir LogToEmailLoggersınıf olarak uygulanan bir arabirim düşünün . LogToEmailLoggerSınıf tüm gösterir ILoggeryöntemleri ve özellikleri, aynı zamanda bir uygulama özgü özelliği var olur sysAdminEmail.

Logger uygulamanızda kullanıldığında, ayarlamak için tüketen kodun endişe olmamalıdır sysAdminEmail. Bu özellik, logger kurulumu sırasında ayarlanmalı ve dünyadan gizlenmelidir.

Somut uygulamaya karşı kodlama yapıyorsanız, kaydediciyi kullanırken uygulama özelliğini yanlışlıkla ayarlayabilirsiniz. Şimdi, uygulama kodunuz günlükçünüze sıkıca bağlı ve başka bir günlükleyiciye geçmek için önce kodunuzun orijinalinden ayrılması gerekiyor.

Bu anlamda, bir arayüze kodlama bağlantıyı gevşetir .

İkinci noktanızla ilgili olarak: Bir arabirime kodlama için gördüğüm bir diğer neden, kodun karmaşıklığını azaltmaktır.

Örneğin, ben şu arayüzlerle bir oyun var düşünün I2DRenderable, I3DRenderable, IUpdateable. Tek bir oyun bileşeninin hem 2B hem de 3B kiralanabilir içeriğe sahip olması nadir değildir. Diğer bileşenler sadece 2D ve diğerleri sadece 3D olabilir.

2B oluşturma tek bir modül tarafından yapılırsa, I2DRenderables koleksiyonunu korumasının anlamı vardır . Koleksiyonundaki nesnelerin de olması önemli değil I3DRenderableveyaIUpdateble diğer modüllerin de nesnelerin bu yönlerini işlemekten sorumlu .

Renderable nesneleri bir liste olarak I2DRenderablesaklamak, oluşturma sınıfının karmaşıklığını düşük tutar. 3B Oluşturma ve Güncelleme mantığı kaygı verici değildir ve bu nedenle alt nesnelerinin bu yönleri göz ardı edilebilir ve göz ardı edilmelidir.

Bu anlamda, bir arayüze kodlama endişeleri izole ederek karmaşıklığı düşük tutar .


4

Burada kullanılan kelime arayüzünün iki kullanımı olabilir. Sorunuzla esas olarak bahsettiğiniz arayüz Java arayüzüdür . Bu özellikle bir Java konseptidir, daha genel olarak bir programlama dili arayüzüdür.

Bir arayüze programlamanın daha geniş bir kavram olduğunu söyleyebilirim. Birçok web sitesi için mevcut olan popüler REST API'leri, daha yüksek seviyedeki bir arayüze yönelik daha geniş programlama konseptinin bir başka örneğidir. Kodunuzun iç işleri ile dış dünya arasında bir katman oluşturarak (Internet'teki insanlar, diğer programlar, aynı programın diğer kısımları bile) dış dünyadakileri değiştirmediğiniz sürece kodunuzdaki herhangi bir şeyi değiştirebilirsiniz. bunun bir arabirim tarafından tanımlandığı veya onurlandırmayı düşündüğünüz bir sözleşme olması bekleniyor.

Bu daha sonra, kendi arayüzünüze bağlı olan diğer tüm şeyleri anlatmanıza gerek kalmadan iç kodunuzu yeniden canlandırma esnekliği sağlar.

Ayrıca, kodunuzun daha kararlı olması gerektiği anlamına gelir. Arayüze bağlı kalarak diğer kişilerin kodlarını kırmamalısınız. Arabirimi gerçekten değiştirmeniz gerektiğinde, yeni sürümün arabiriminde değişikliklerin değiştiğini işaret eden API'nin yeni bir ana sürümünü (1.abc - 2.xyz) serbest bırakabilirsiniz.

@Doval'ın bu cevaptaki yorumunda işaret ettiği gibi, hataların da yeri vardır. Bunların hepsinin enkapsülasyona kaynadığını düşünüyorum. Nesneye Yönelik tasarımdaki nesneler için kullanacağınız gibi, bu konsept de daha yüksek düzeyde faydalıdır.


1
Genellikle göz ardı edilen bir avantaj, hataların yeridir. Bir Haritaya ihtiyacınız olduğunu ve onu bir ikili ağaç kullanarak uyguladığınızı söyleyin. Bunun çalışması için, anahtarların bazı sıralara sahip olması gerekir ve mevcut düğümün anahtarı "daha az" olan anahtarların sol alt ağaç üzerinde, "daha büyük" anahtarlar açıkken değişmezliğini korumanız gerekir. sağ alt ağaç. Harita uygulamasını bir arayüzün arkasına gizlerseniz, bir Harita araması yanlış giderse, hatanın Harita modülünde olması gerektiğini bilirsiniz . Eğer ortaya çıkarsa, hata programın herhangi bir yerinde olabilir . Bana göre, bu ana yararı.
Doval

4

Gerçek Dünya analojisi yardımcı olabilir:

Bir Arayüzdeki bir elektrik fişi.
Evet; TV'nizden, radyodan, elektrikli süpürgeden, çamaşır makinesinden vb.

Bir ana fişi olan herhangi bir cihaz (örneğin, aletler arayüzü "bir şebeke fişinin sahip") olarak muamele edilebilir tam olarak aynı şekilde; hepsi bir duvar prizine takılabilir ve o soketten güç çekebilir.

Her cihazın ne yaptığı tamamen farklı. Halılarınızı TV ile temizlemekte çok fazla bir şey istemeyeceksiniz ve çoğu kişi çamaşır makinelerini eğlence için izlemiyor. Ancak bu cihazların tümü bir prize takılmanın genel davranışını paylaşır.

Arayüzlerin size sağladığı şey budur. Kalıtımın komplikasyonlarına ihtiyaç duymadan birçok farklı Nesne Sınıfı tarafından gerçekleştirilebilecek
birleşik davranışlar .


1

"Bir arayüze programlama" terimi çok fazla açıklamaya açıktır. Yazılım geliştirmede arayüz çok yaygın bir kelimedir. Kavramı yıllar boyunca eğittiğim genç geliştiricilere nasıl açıklayacağım.

Yazılım mimarisinde çok çeşitli doğal sınırlar vardır. Ortak örnekler

  • İstemci ve sunucu işlemleri arasındaki ağ sınırı
  • Bir uygulama ile bir üçüncü taraf kütüphanesi arasındaki API sınırı
  • Programdaki farklı işletme alanları arasındaki iç kod sınırı

Önemli olan, bu doğal sınırlar var olduğunda, tanımlanmış olmaları ve bu sınırın nasıl davrandığının sözleşmesinin belirtilmesidir. Yazılımınızı "diğer tarafın" davranıp davranmayacağına değil, etkileşimlerinizin şartnameye uygun olup olmadığına göre test edersiniz.

Bunun sonuçları:

  • Harici bileşenler, şartnameyi uyguladıkları sürece değiştirilebilir
  • Doğru davranışı doğrulamak için birim testleri için doğal nokta
  • Entegrasyon testleri önemli hale geldi - şartname belirsiz miydi?
  • Bir geliştirici olarak, belirli bir görev üzerinde çalışırken daha küçük bir endişe dünyasına sahipsiniz.

Bunların çoğu sınıflar ve arayüzlerle ilgili olsa da, bunun veri modelleri, ağ protokolleri ve birden fazla geliştiriciyle çalışmanın daha genel bir şekilde olduğunu da anlamak önemlidir.

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.