Arabirimi temel sınıfla aynı dosyada bildirmek iyi bir pratik mi?


29

Değiştirilebilir ve test edilebilir olmak için normalde mantıkla hizmetlerin bir arayüze sahip olması gerekir, örneğin

public class FooService: IFooService 
{ ... }

Tasarım açısından buna katılıyorum, ama bu yaklaşımla beni rahatsız eden şeylerden biri, bir hizmet için iki şeyi (sınıf ve arayüz) ve ekibimizde normalde iki dosya (bir dosya) bildirmeniz gerekecek sınıf için ve arayüz için bir tane). Başka bir rahatsızlık, navigasyondaki zorluktur, çünkü IDE'de (VS2010) "Tanıma git" kullanımı, gerçek sınıfa değil, diğer sınıflar arayüze atıfta bulunduğundan arayüze işaret edecektir.

IFooService'i FooService ile aynı dosyaya yazmanın yukarıdaki tuhaflığı azaltacağını düşünüyordum. Sonuçta, IFooService ve FooService çok ilişkili. Bu iyi bir uygulama mı? IFooService'in kendi dosyasında bulunmasının iyi bir nedeni var mı?


3
Belirli bir arabirimin yalnızca bir uygulamasına sahipseniz, arabirim için gerçek bir mantıksal gereksinim yoktur. Neden sınıfı doğrudan kullanmıyorsunuz?
Joris Timmermans

11
Gevşek kaplin ve test edilebilirlik için @MadKeithV?
Louis Rhys

10
@MadKeithV: haklısın. Eğer IFooService dayanır kodu için birim testleri yazarken Fakat, genellikle bir MockFooService sağlayacaktır olan bu arabirim ikinci uygulanması.
Doktor Brown,

5
@DocBrown - Birden fazla uygulamanız varsa, açıkçası yorum yok olur, ancak doğrudan “tek uygulamaya” gidebilmenin faydası da olur (çünkü en az iki tane vardır). O zaman soru şu olur: somut uygulamada, arayüzü kullandığınız noktada arayüz tanımında / dokümantasyonunda bulunmaması gereken hangi bilgiler var?
Joris Timmermans

1

Yanıtlar:


24

Kendi dosyasında olmak zorunda değildir, ancak ekibiniz bir standarda karar vermeli ve buna bağlı kalmalıdır.

Ayrıca, “Tanıma git” seçeneğinin sizi arabirime götürmesi konusunda haklısınız, ancak Resharper yüklüyse, bu arabirimden türetilmiş sınıfların / arabirimlerin bir listesini açmak için yalnızca bir tık yeterlidir; Bu yüzden arayüzü ayrı bir dosyada tutuyorum.

 


5
Bu cevaba katılıyorum, tüm IDE tasarımlarımıza uyum sağlasa da tam tersi olmaz, değil mi?
marktani 11:12

1
Ayrıca, Resharper olmadan, F12 ve Shift + F12 hemen hemen aynı şeyi yapar. Sağ tık bile olmaz :) (dürüst olmak gerekirse, sizi yalnızca arayüzün kullanımlarını yönlendirir, Resharper sürümünün ne yaptığından emin olmaz)
Daniel B

@DanielB: Resharper'da, Alt-End uygulamaya geçiyor (veya uygulanacak olası uygulamaların bir listesini sunuyor).
StriplingWarrior

@ StriplingWarrior o zaman vanilya VS'nin de yaptığı gibi görünüyor. F12 = tanımlamaya git, ÜstKrkt + F12 = uygulamaya git En kullanışlı gezinme kısayollarından biri, sadece kelimeyi yayıyorum.
Daniel B,

@DanielB: Shift-F12 için varsayılan "kullanımları bulma" dır. jetbrains.com/resharper/webhelp/…
StriplingWarrior

15

Bence onları ayrı dosyalar halinde tutmalısın. Dediğiniz gibi, fikir test edilebilir ve değiştirilebilir kalmaktır. Arabirimi uygulamanızla aynı dosyaya yerleştirerek, arabirimi belirli bir uygulamayla ilişkilendirirsiniz. Sahte bir nesne veya başka bir uygulama oluşturmaya karar verirseniz, arayüz FooService'ten mantıksal olarak ayrı olmayacaktır.


10

SOLID’e göre, sadece arayüzü yaratmanız değil, sadece farklı bir dosyada olması değil, farklı bir montajda olması gerekir.

Niye ya? Çünkü bir derleme içinde derlenen bir kaynak dosyasındaki herhangi bir değişiklik, derlemenin yeniden derlenmesini gerektirir ve bir derlemede yapılan herhangi bir değişiklik, herhangi bir bağımlı derlemenin yeniden derlenmesini gerektirir. Öyleyse, SOLID tabanlı amacınız, bir uygulama A'yı bir uygulama B ile değiştirebiliyorsa, C sınıfı arayüze bağlıysa, farkı bilmek zorunda kalmazsam, benimle montajdan emin olmalısınız. İçinde değişmez, dolayısıyla kullanımları korur.

“Ama sadece bir derleme” Protesto ettiğini duydum. Öyle olabilir, ancak akıllı telefonunuzdaki uygulamada, kullanıcılarınızın veri bant genişliğinde daha kolay; değiştirilen bir ikili dosya indirme mi, yoksa o ikiliyi ve kodun bağlı olduğu beş kodunu indirme mi? Her program bir LAN üzerindeki masaüstü bilgisayarlar tarafından tüketilmek üzere yazılmaz. Bant genişliğinin ve hafızanın ucuz olduğu durumlarda bile, daha küçük yama sürümleri değere sahip olabilir, çünkü Active Directory veya benzeri etki alanı yönetimi katmanları aracılığıyla tüm LAN'a itme konusunda önemsizdir; kullanıcılarınız, tümünün yeniden yüklenmesi için birkaç dakika yerine tekrar oturum açtıklarında uygulanmaları için yalnızca birkaç saniye bekleyeceklerdir. Bir proje inşa ederken derlenmesi gereken daha az meclis ne kadar hızlı olursa,

Şimdi, feragatname: Bu her zaman mümkün veya yapmak mümkün değildir. Bunu yapmanın en kolay yolu, merkezi bir “arayüzler” projesi oluşturmaktır. Bunun kendi olumsuz tarafları var; Arayüz projesi ve uygulama projesine uygulamanızın kalıcılık katmanını veya diğer önemli bileşenlerini yeniden kullanan diğer uygulamalarda referans verilmesi gerektiğinden kod daha az yeniden kullanılabilir hale gelir. Arayüzleri daha sıkı bağlı düzeneklere bölerek bu sorunun üstesinden gelebilirsiniz, ancak daha sonra uygulamanızda tam bir yapıyı çok acı verici yapan daha fazla projeniz var. Anahtar dengedir ve gevşek bağlı tasarımın korunması; Genellikle dosyaları gerektiği gibi taşıyabilirsiniz, böylece bir sınıfın birçok değişikliğe ihtiyaç duyacağını ya da bir arayüzün yeni uygulamalarının düzenli olarak gerekli olacağını göreceksiniz (belki de diğer yazılımların yeni desteklenen sürümleriyle arayüz oluşturmak için,


8

Neden ayrı dosyalar rahatsızlık veriyor? Benim için çok daha temiz ve temiz. Solution Explorer'da daha az dosya görmek istiyorsanız, "Arayüzler" adlı bir alt klasör oluşturmak ve IFooServer.cs dosyalarınızı buraya yapıştırmak yaygındır.

Arabirimin kendi dosyasında tanımlanmasının nedeni, sınıfların genellikle kendi dosyalarında tanımlanmasının sebebidir: mantıksal yapınız ve dosya yapınız aynı olduğunda proje yönetimi daha kolaydır, böylece belirli bir sınıfın hangi dosyanın tanımlandığını her zaman bilirsiniz. Bu hata ayıklama sırasında (istisna yığın izleri genellikle size dosya ve satır numaralarını verir) veya kaynak kodunu bir kaynak kontrol havuzunda birleştirirken hayatınızı kolaylaştırabilir.


6

Kod dosyalarınızın yalnızca tek bir sınıf veya tek bir arabirim içermesine izin vermek genellikle iyi bir uygulamadır. Ancak bu kodlama uygulamaları bir son için bir araçtır - kodunuzu çalışmayı kolaylaştırarak daha iyi yapılandırmak için. Siz ve ekibiniz, sınıflar kendi ara yüzleriyle bir arada tutulursa, bununla uğraşmayı kolay bulursunuz.

Şahsen sizin durumunuzda olduğu gibi arayüzü uygulayan tek bir sınıf varken arayüzü ve sınıfın aynı dosyada olmasını tercih ederim.

Navigasyonla ilgili problemlerinizle ilgili olarak ReSharper'ı şiddetle tavsiye edebilirim . Belirli bir arabirim yöntemini uygulayan yönteme doğrudan atlamak için çok yararlı bazı kısayollar içerir.


3
Takım uygulamalarının dosya yapısını dikte etmesi ve norm yaklaşımına aykırı olması gerektiğini belirtmek için +1.

3

Arayüzünüzün sadece sınıfa ayrı bir dosyada değil, hatta tamamen ayrı bir montajda olmasını istediğiniz birçok zaman vardır .

Örneğin, bir WCF Servis Sözleşmesi arayüzü , telin her iki ucunda da kontrolünüz varsa, hem müşteri hem de servis tarafından paylaşılabilir . Arabirimi kendi düzeneğine taşıyarak, kendi kendine daha az sayıda montaj bağımlılığı olacaktır. Bu, müşterinin tüketmesini kolaylaştırarak kaplini uygulaması ile gevşetir.


2

Nadiren, eğer varsa, bir arayüz 1 tek bir uygulaması olması mantıklı . Bir ortak arayüzü ve bu arayüzü aynı dosyaya uygulayan bir genel sınıf koyarsanız, iyi bir olasılık, bir arayüze ihtiyaç duymamanızdır.

Arayüzle birlikte konumlandırdığınız sınıf soyut olduğunda ve arayüzünüzün tüm uygulamalarının o soyut sınıfı miras alması gerektiğini bildiğiniz zaman, ikisini aynı dosyada bulmak mantıklı olur. Arabirim kullanma kararınızı yine de incelemelisiniz: soyut bir sınıfın iyi olup olmadığını kendinize sorun ve cevap olumluysa ara yüzü bırakın.

Genel olarak, yine de, "bir ortak sınıf / arayüz tek bir dosyaya karşılık gelir" stratejisine bağlı kalmalısınız: stratejisi takip etmek kolaydır ve kaynak ağacınızın gezinmesini kolaylaştırır.


1 Dikkat çeken bir istisna, test amaçlı bir arayüze sahip olmanız gerektiğidir, çünkü alaycı çerçeve seçiminiz bu ek gereksinimi kodunuza yerleştirmiştir.


3
Aslında, ünite testlerinin bağımlılıkları ikame etmeleri, saplamalar, spys ya da diğer test çiftleri ile değiştirmesine izin verdiği için .NET'te bir sınıf için bir arayüze sahip olması oldukça normal bir kalıptır.
Pete

2
@Pete Bunu bir not olarak eklemek için cevabımı düzenledim. Bu kalıbı "normal" olarak adlandırmazdım çünkü test edilebilirliğin ana kod tabanınıza "sızıntı" ile ilgili olmasını sağlar. Modern alaycı çerçeveler, bu problemi büyük ölçüde aşmanıza yardımcı olur, ancak orada bir arayüze sahip olmak kesinlikle işleri çok kolaylaştırır.
dasblinkenlight 11:12

2
@KeithS Arabirimi olmayan bir sınıf, tasarımınızda yalnızca alt sınıflamanın bir anlamı olmadığından emin olmadığınızda ve o sınıfı oluşturduğunuzdan emin olmalıdır sealed. Gelecekte bir süre sonra ikinci bir alt sınıf ekleyebileceğinizden şüpheleniyorsanız, hemen bir arayüz ekleyin. PS İyi kalitede bir refactoring asistanı, tek bir ReSharper lisansının mütevazı bir fiyata sizin olabilir :)
dasblinkenlight

1
@KeithS Ve evet, alt sınıflandırma için özel olarak tasarlanmamış tüm sınıflarınız mühürlenmelidir. Aslında, dilek sınıfları varsayılan olarak mühürlendi ve sizi miras sınıflarını açıkça belirtmeye zorladı; aynı şekilde dilin sizi onları işaretleyerek geçersiz kılmak için işlevleri atamaya zorlar virtual.
dasblinkenlight 11:12

2
@KeithS: Bir uygulamanız iki olduğunda ne olur? Uygulamanızın değiştiği zamankiyle aynı; Bu değişikliği yansıtacak şekilde kodu değiştirirsiniz. YAGNI burada geçerlidir. Gelecekte neyin değişeceğini asla bilemezsiniz, bu yüzden mümkün olan en basit şeyi yapın. (Ne yazık ki bu maxim ile karışıklık test)
Groky

2

Arayüzler, Müşterilere aittir, Robert C. Martin tarafından Çevik İlkeler, Uygulamalar ve Desenler bölümünde tanımlandığı gibi uygulamalarına değil. Bu nedenle, arayüz ile uygulamayı aynı yerde birleştirmek ilkesine aykırıdır.

Müşteri kodu arayüze bağlıdır. Bu , uygulama olmadan müşteri kodunu ve arayüzü derleme ve dağıtma olanağını sağlar . Müşteri koduna eklentiler gibi çalışan farklı uygulamalarınız olabilir .

GÜNCELLEME: Buradaki çevik sadece bir ilke değil. 'Tasarım Desenlerinde Dörtlü Çete, '94'te, arayüzlere bağlı kalan ve arayüzlere programlama yapan müşterilerden bahsediyor. Görüşleri benzer.


1
Arayüzlerin kullanımı, Çevik'in sahip olduğu alanın çok ötesine geçer. Çevik, dil yapılarını belirli şekillerde kullanan bir geliştirme metodolojisidir. Arayüz bir dil yapısıdır.

1
Evet, ancak arayüz hala müşteriye aittir ve çevikten bahsettiğimizden veya söylemememizden bağımsız olarak uygulamaya aittir.
Patkos Csaba

Bu işte seninleyim.
Marjan Venema

0

Şahsen bir arayüzün önündeki "Ben" i beğenmedim. Böyle bir tipte bir kullanıcı olarak bunun bir arayüz olup olmadığını görmek istemiyorum. Tip ilginç bir şey. Bağımlılık açısından FooService, IFooService'in BİR olası uygulamasıdır. Arayüz, kullanıldığı yere yakın olmalıdır. Diğer taraftan, uygulama müşteriyi etkilemeden kolayca değiştirilebileceği bir yerde olmalıdır. Bu yüzden iki dosyayı tercih ederim - normalde.


2
Bir kullanıcı olarak, bir türün bir arabirim olup olmadığını bilmek istiyorum, örneğin, onunla kullanamayacağım anlamına gelir new, ancak diğer taraftan, birlikte veya tersine kullanabileceğim anlamına gelir. Ve. INet'te yerleşik bir adlandırma kuralıdır, bu nedenle, yalnızca diğer türlerle tutarlı olması durumunda buna uymak için iyi bir nedendir.
svick

IArabirimden başlamak , sadece iki dosyadaki ayrılık hakkındaki argümanlarıma giriş oldu. Kod daha iyi okunur ve bağımlılıkların tersine çevrilmesi daha net hale gelir.
Ollins

4
Beğenin ya da beğenmeyin, bir arabirim adının önünde bir 'I' kullanmak, .NET'te fiili bir standarttır. Bir .NET projesinde standarda uymamak, benim görüşüme göre 'en az şaşkınlık ilkesinin' ihlali anlamına gelir.
Pete

Asıl noktam: iki dosyada ayrı. Biri soyutlama, diğeri uygulama için. Kullanımı ise Iortamınızda normaldir: kullanın! (Ama hoşuma
gitmedi

P.SE örneğinde, bir arabirimin önünde I öneklenmesi, posterin başka bir sınıftan miras almadan bir arabirimden bahsettiğini daha belirgin hale getirir.

0

Arayüzlere kodlama yapmak kötü olabilir, aslında bazı bağlamlar için bir anti-kalıp olarak kabul edilir ve bir yasa değildir. Genellikle, anti-pattern arabirimlerine kodlamanın iyi bir örneği, uygulamanızda yalnızca bir uygulaması olan bir arabirime sahip olmanızdır. Bir diğeri, eğer arayüz dosyası o kadar rahatsız edici hale gelirse, uygulanan sınıfın dosyasındaki bildirimini gizlemek zorunda kalırsınız.


Bir arabirim uygulamanızda yalnızca bir uygulamaya sahip olmak mutlaka kötü bir şey değildir; biri uygulamayı teknoloji değişimlerine karşı koruyor olabilir. Örneğin, veri kalıcılık teknolojisi için bir arayüz. Uygulamanın değişmesi durumunda uygulamayı korurken mevcut veri kalıcılığı teknolojisi için yalnızca bir uygulamaya sahip olacaksınız. Yani o zaman sadece tek bir imp olacaktır.
TSmith

0

Bir sınıfı ve bir arayüzü aynı dosyaya koymak, her ikisinin de nasıl kullanılabileceğine dair hiçbir sınır getirmez. Bir arayüz hala uygulayan bir sınıfla aynı dosyada olsa bile, alaylar vb. İle aynı şekilde kullanılabilir. Bu soru tamamen örgütsel kolaylıklardan biri olarak algılanabilir; bu durumda hayatınızı kolaylaştıracak her şeyi yapın derim!

Elbette, ikisi de aynı dosyada bulunmasının, gerçekte olduklarından daha programatik olarak eşleşmiş olmalarını isteme konusunda hevesli olabileceğini savunabilir, bu bir risktir.

Şahsen, bir sözleşmeyi diğerine kullanan bir kod temeli ile karşılaştığımda, iki şekilde de endişelenmem.


Bu sadece bir "örgütsel kolaylık" değil, aynı zamanda risk yönetimi, dağıtım yönetimi, kod izlenebilirliği, değişim kontrolü, kaynak kontrolü gürültüsü, güvenlik yönetimidir. Bu sorunun pek çok açısı var.
TSmith
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.