Yöntemlerin yalnızca argüman adıyla (tür değil) ayırt edilmesi yeterli mi?


36

Yöntemlerin yalnızca argüman adıyla (tür değil) ayırt edilmesi yeterli mi yoksa daha açık bir şekilde adlandırılması daha mı iyi?

Örneğin T Find<T>(int id)vs T FindById<T>(int id).

ByIdSadece argüman adını tutmak vs daha açık bir şekilde adlandırmak için herhangi bir iyi sebep var mı ?

Düşünebilmemin bir nedeni, yöntemlerin imzalarının aynı olması ancak farklı bir anlama sahip olmalarıdır.

FindByFirstName(string name) ve FindByLastName(string name)


4
Öyleyse eklemek için Bul'u bulduğunuzda T Find<T>(string name)veya (int size)kaçınılmaz sorunları nasıl çözmeyi planlıyorsunuz?
UKMonkey

3
@UKMonkey kaçınılmaz ne sorun var?
Konrad

3
ilk durumda: eğer birden fazla giriş aynı ada sahipse, fonksiyon imzasını değiştirmeniz gerekecektir; Bu, insanların muhtemelen geri dönüşün ne olduğu ile karıştırılacağı anlamına gelir; İkinci durumda, argüman aynıdır - ve dolayısıyla yasadışı bir aşırı yüklenme. Fonksiyonu "byX" ile adlandırmaya başlar veya aynı argümanla aşırı yük eşdeğerine sahip olabilmek için argüman için bir nesne yaratırsınız. Her ikisi de farklı durumlar için iyi çalışır.
UKMonkey

2
@UKMonkey, isterseniz bazı kod örnekleriyle birlikte bir cevap gönderebilirsiniz
Konrad

3
ID'ler muhtemelen bir opak IDnesne olmalı ve sadece bir değil int. Bu şekilde derleme zamanını, kodunuzun bir bölümünde int veya viceversa için bir kimlik kullanmadığınızdan kontrol edin. Ve bununla sahip olabilir find(int value)ve find(ID id).
Bakuriu

Yanıtlar:


68

Elbette daha açık bir şekilde isimlendirmek için iyi bir neden var.

Öncelikle kendi kendini açıklayıcı olması gereken yöntem tanımı değil, yöntem kullanımıdır . Ederken findById(string id)ve find(string id)kendini açıklayıcı hem, arasında büyük bir fark vardır findById("BOB")ve find("BOB"). Eski durumda, rastgele hazır bilginin aslında bir İD olduğunu biliyorsunuz. İkinci durumda, emin değilsiniz - aslında verilen bir isim veya tamamen başka bir şey olabilir.


9
Eğer bir değişken veya özellik adı referans noktasıdır sahip diğer vakaların% 99 hariç: findById(id)vs find(id). Bu şekilde iki yönlü gidebilirsiniz.
Greg Burghardt

16
@GregBurghardt: Belirli bir değer mutlaka bir yöntem ve arayan için aynı şekilde adlandırılmış değildir. Örnek vermek gerekirse, double Divide(int numerator, int denominator)bir yöntemde kullanılır: double murdersPerCapita = Divide(murderCount, citizenCount). Aynı değişken ismini kullanan iki yönteme güvenemezsiniz, bunun olmadığı durumlarda birçok dava vardır (veya durum söz konusu olduğunda kötü adlandırmadır)
Flater

1
@Flater: Söz konusu kod göz önüne alındığında (bir tür kalıcı depolama alanından malzeme bulma) Bu yöntemi bir "murderedCitizenId" veya "citizenId" ile çağırabileceğinizi hayal ediyorum. burada belirsiz. Ve dürüst olmak gerekirse, ben de bu şekilde gidebilirim. Bu aslında çok tartışılan bir soru.
Greg Burghardt

4
@GregBurghardt: Genel bir kuralı tek bir örnekten damlatamazsınız. OP'nin sorusu genel olarak verilen örneğe özgü değildir. Evet, aynı adın kullanılmasının anlamlı olduğu bazı durumlar vardır, fakat aynı zamanda anlamadığı durumlar da vardır. Bu nedenle, bu cevap, bir alt kullanım durumunda gerekli olmasa bile tutarlılığı hedeflemenin en iyisidir .
Flater

1
Ad parametreleri , yöntem tanımına bakmanız gerektiğinden, karışıklık zaten mevcut olduktan sonra karışıklığı giderir, açıkça adlandırılmış yöntemler ise yöntem yöntem çağrısında mevcut olan isme sahip olduktan sonra karışıklığı önler . Ayrıca, aynı ad ve argüman tipinde fakat farklı argüman adında iki metoda sahip olamazsınız; bu, belirli durumlarda zaten açık isimlere ihtiyaç duyacağınız anlamına gelir.
Darkhogg

36

FindById () 'in Avantajları .

  1. Gelecek geçirmezlik : Birlikte başlarsanız Find(int), daha sonra diğer yöntemleri (eklemek zorunda FindByName(string), FindByLegacyId(int), FindByCustomerId(int), FindByOrderId(int), vb), benim gibi insanlar arayan yaş harcama eğilimi FindById(int). Gerçekten bir sorun varsa yapabilirsiniz ve değişecek Find(int)için FindById(int)gerekli hale geldiğinde - Gelecek yalıtımı bu hakkındadır eğer s.

  2. Okuması daha kolay . Findmükemmel para gibi çağrı görünüyor eğer olduğunu record = Find(customerId);Oysa FindByIdöyle olmadığını okumak için biraz daha kolaydır record = FindById(AFunction());.

  3. Tutarlılık . FindByX(int)/ FindByY(int)Desenini her yere tutarlı bir şekilde uygulayabilirsiniz , fakat Find(int X)/ Find(int Y)mümkün olmadıkları için çatışma vardır.

Find () 'ın Avantajları

  • ÖPMEK. Findbasit ve anlaşılır ve operator[]bunun yanında bu bağlamda en çok beklenen 2 işlev adından biri. (Bazı popüler alternatifler olmak get, lookupya da fetchiçeriğe bağlı).
  • Genel bir kural olarak, işlevin ne yaptığını doğru şekilde tanımlayan iyi bilinen tek bir kelime olan bir işlev adınız varsa, onu kullanın. Fonksiyonun ne yaptığını açıklamakta biraz daha iyi olan daha uzun kelimeli bir isim olsa bile. Örnek: Uzunluk vs NumberOfElements . Bir takas var ve çizgiyi nereye çekmeliyiz devam eden bir tartışmaya tabi.
  • Artıklıktan kaçınmak genellikle iyidir. Biz bakarsak FindById(int id), biz kolayca bunu değiştirerek fazlalık kaldırabilir Find(int id), ancak bir ters orantı vardır - biz netliğinde azalma.

Alternatif olarak , güçlü bir şekilde yazılan kimlikleri kullanarak her ikisinden de yararlanabilirsiniz :

CustomerRecord Find(Id<Customer> id) 
// Or, depending on local coding standards
CustomerRecord Find(CustomerId id) 

Uygulama Id<>: C #'ya kesinlikle ID değerleri girerek

Buradaki ve yukarıdaki bağlantıdaki yorumlar, Id<Customer>ele almak istediğimle ilgili birçok endişeyi dile getirdi :

  • Endişe 1: Bu bir jenerik kötüye kullanımıdır. CustomerIdve OrderIDfarklı türlerdir ( customerId1 = customerId2;=> iyi, customerId1 = orderId1;=> kötü), ancak uygulamaları neredeyse aynıdır, bu yüzden bunları kopyala yapıştır veya metaprogramming ile uygulayabiliriz. Jeneriklerin açığa çıkarılması veya saklanmasıyla ilgili bir tartışmada değer varken, metaprogramlama jenerik için ne işe yarar.
  • Endişesi 2: Basit hataları durdurmaz. / Bir problem arayışında bir çözüm Bu, güçlü şekilde yazılmış kimlikleri kullanarak kaldırılan asıl mesele, yapılan çağrıda yanlış tartışma sırasıdır DoSomething(int customerId, int orderId, int productId). Kesin olarak yazılmış kimlikleri, sorulan OP de dahil olmak üzere diğer sorunları da önler.
  • Endişe 3: Bu gerçekten sadece kodu gizler. Bir kimliğin tutulup tutulmadığını söylemek zor int aVariable. Bir Kimlik'in tutulduğunu söylemek kolaydır Id<Customer> aVariableve bunun bir müşteri kimliği olduğunu bile söyleyebiliriz.
  • Endişe 4: Bu kimlikler güçlü türler değil, yalnızca paketleyicilerdir. Stringetrafında sadece bir sarıcı byte[]. Sarma veya kapsülleme, güçlü yazma ile çakışmaz.
  • Endişe 5: Tamamlandı. Ben ekleyerek tavsiye edersiniz rağmen İşte asgari versiyonu var operator==ve operator!=sen dayanmak istemiyorsanız, hem de Equals:

.

public struct Id<T>: {
    private readonly int _value ;
    public Id(int value) { _value = value; }
    public static explicit operator int(Id<T> id) { return id._value; }
}

10

Bunu düşünmenin bir başka yolu dilin güvenliğini kullanmaktır.

Gibi bir yöntem uygulayabilirsiniz:

Find(FirstName name);

Burada FirstName, ilk adı içeren bir dizgiyi saran ve nesnenin ne yaptığıyla veya ne denildiği argümanlarıyla ilgili hiçbir karışıklık olmadığı anlamına gelen basit bir nesnedir.


4
OP'nin sorusuna cevabınızın ne olduğundan emin değilim. Argümanın türüne dayanarak "Bul" gibi bir ad kullanmanızı öneririz. Yoksa bu tür isimleri sadece argümanlar için açık bir tip olduğunda ve başka bir yerde "FindById" gibi daha açık bir isim kullanmanız önerilir mi? Yoksa "Bul" gibi bir adı daha uygulanabilir kılmak için açık türler eklemeyi mi tavsiye ediyorsunuz?
Doktor Brown

2
@DocBrown Ben ikincisini düşünüyorum ve onu seviyorum. Aslında Peter'ın cevabına benzer, iiuc. Anladığım kadarıyla mantık iki katıdır: (1) İşlevin ne yaptığı argüman türünden açıktır; (2) string name = "Smith"; findById(name);Tanımlayıcı olmayan genel türler kullanırsanız, mümkün olan gibi hatalar yapamazsınız .
Peter - Monica

5
Genel olarak, derleme zamanı tür güvenliği konusunda bir hayranıysam, sarıcı tiplerine dikkat edin. Tip güvenliği için sarıcı sınıflarının tanıtılması, fazla yapılması durumunda API'nizi zaman zaman ciddi şekilde karmaşık hale getirebilir. örneğin, "eskiden int olarak bilinen sanatçı" problemi; Uzun vadede çoğu insanın sonsuz DWORD LPCSTRvb. klonlara baktığını ve "bunun bir int / string / etc" olduğunu düşündüğünü söyleyebilirim, araçlarınızı geliştirmek için zaman harcayacağınız noktaya geliyor .
jrh

1
@jrh Doğru. “Nominal” tiplerin (sadece isme göre farklılık gösteren) tanıtılması konusundaki litmus testim, kullanım durumumuzda ortak fonksiyonların / metotların bir anlam ifade etmemesidir, örneğin int, ID'ler için anlamsız olan sık sık toplanır, çarpılır vb. bu yüzden IDayırt etmek istiyorum int. Bu, bir değer verebileceğimiz şeyi daraltmak suretiyle bir API'yi basitleştirebilir (örneğin, eğer varsa ID, sadece findörneğin, ageveya ile çalışamaz highscore). Tersine, kendimizi çok fazla dönüştürdüğümüzü veya findbirden fazla tür için aynı işlevi / yöntemi (örneğin )
yazdığımızı

1

FindByID .... gibi açıklayıcı bir bildiri için oy kullanacağım. Açık ve kapalı olmalıdır (SOLID). Bu yüzden sınıf, FindByName .. vb.

Ancak FindByID kapatıldı ve uygulaması birim test edildi.

Tahminlerle yöntemler önermeyeceğim, bunlar genel seviyede iyi. Ya alana göre (ByID) farklı metodolojiye sahipseniz.


0

Hiç kimsenin aşağıdaki gibi bir yüklem kullanmasını önermediğine şaşırdım:

User Find(Predicate<User> predicate)

Bu yaklaşımla yalnızca API'nizin yüzeyini düşürmezsiniz, aynı zamanda onu kullanan kullanıcıya daha fazla kontrol sağlar.

Bu yeterli değilse, her zaman gereksinimlerinize göre genişletebilirsiniz.


1
Sorun, endeksler gibi şeylerden yararlanamadığı için daha az verimli olmasıdır.
Solomon Ucko
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.