Aşırı yüklenmiş yöntemleri yeniden adlandırmalı mıyız?


14

Bu yöntemleri içeren bir arayüz olduğunu varsayın:

Car find(long id);

List<Car> find(String model);

Bunları bu şekilde yeniden adlandırmak daha iyi mi?

Car findById(long id);

List findByModel(String model);

Aslında, bu API'yı kullanan herhangi bir geliştiricinin, başlangıç find()yöntemlerinin olası argümanlarını bilmek için arayüze bakması gerekmez .

Yani sorum daha genel: Okunabilirliği azalttığı için kodda aşırı yüklenmiş yöntemleri kullanmanın faydası nedir?


4
Tutarlı olduğunuz sürece her iki yöntem de kabul edilebilir.
ChrisF

Aşırı yükleme ve bir yöntemi geçersiz kılma arasında bir ilişki vardır. Ancak bu makale önerinizi desteklemektedir
İlginizi

Yanıtlar:


23

Bu, duyarlı olabileceğiniz diğer birçok kötü okunabilirlik uygulamasına kıyasla nispeten küçük bir konudur, bu yüzden yöntemlerinizi nasıl adlandırdığınızın çoğunlukla bir zevk meselesi olduğunu söyleyebilirim.

Bununla birlikte, eğer bu konuda bir şeyler yapacaksanız, bu uygulamayı takip ederim:

  • Aşırı yüklerse ...

    Yöntemler neredeyse aynı sözleşmeye uyar, ancak yalnızca farklı girdilerle çalışır (hesabınızı kişisel vergi kimlik numaranıza, hesap numaranıza veya adınız ve doğum gününüze bakabilen bir telefon operatörü hayal edin). Bu , aynı çıktı türünün döndürülmesini de içerir .

  • Aşağıdaki durumlarda farklı bir ad kullanın ...

    Yöntemler önemli ölçüde farklı şeyler yapar veya farklı çıktılar döndürür (davanız gibi). Veritabanına erişir ve diğeri erişmezse, farklı bir ad kullanmayı düşünebilirsiniz.

    Buna ek olarak, döndürülen tür farklıysa, ben de fiili değiştirmek için değiştirmek için:

    Car findById(long id);
    
    List findAllByModel(String model);
    

3
FWIW, biraz daha güçlü bir şekilde şunu söyleyebilirim: "Yöntemler tamamen aynı sözleşmeye uyuyor ..." Yani argüman türü / sayısı önemli değil - işlev çağrısının semantiği ne olursa olsun aynı. Bağımsız değişken türü / sayısı önemliyse, aşırı yüklenmemelisiniz.
mcmcc

4

Her durumda farklı bir isim kullanmanızı öneririm. İleride bir zamanda List<Car> findByMake(String make), aksine, başka bir yöntem eklemek isteyeceksiniz List<Car> findByModel(String model). Birdenbire, her şeyi çağırmak findmantıklı gelmiyor. Adlarının nasıl kullanılması gerektiği hakkında daha fazla bilgi vermesi durumunda yöntemlerinizin yanlışlıkla kullanılması daha az olasıdır.


1
Adil olmak gerekirse, işlevsellik nesneler tarafından daha açık bir şekilde temsil ediliyorsa, bu kadar bir sorun olmazdı: find(Make val)ve find(Model val). O zaman, findByMake(String val)ne gibi kolaylık yöntemleri gerçekte ne yaptıklarını çok daha açık hale getirecektir. Sonuçta, a Stringya bir marka ya da model değildir, bu yüzden yöntem gerçekten ne yaptığını açıklamalıdır.
Nicole

4

Bir yöntemi yeniden adlandırırsanız, artık aşırı yüklenmeyecektir. Kendi başına aşırı yükleme, kodu daha az okunabilir kılmaz, ancak sözdizimi net değilse uygulamayı takip etmeyi zorlaştırabilir.

Birçok dil, parametrelerin isteğe bağlı olabileceği ve isteğe bağlı parametrelerin varsayılanlarının ima edildiği bir işlevsellik arabirimi sunmak için yöntem aşırı yüklemesini kullanır. Bu, özellikle yöntem bildiriminde varsayılan parametre sözdizimini desteklemeyen diller için geçerlidir.

Yani bunu yapıyor:

void MyMethod(int param1, int param2 = 10)
{
    ...
}

sizi bunu yapmaktan kurtarır:

void MyMethod(int param1)
{
    MyMethod(param1, Param2Default);
}

void MyMethod(int param1, int param2)
{
    ....
}

Hangisinin daha okunabilir olduğu konusunda, bu gerçekten size geliyor. Şahsen ikinci seçeneği tercih ediyorum, özellikle parametre listesi biraz uzun sürüyor, ancak API'nız boyunca tutarlı olduğunuz sürece gerçekten önemli olmadığını düşünüyorum.

Aşırı yükleme ile ilgili zorluk, esasen aynı şeyi yapan ve parametre listelerinin aynı olmasını istediğiniz fonksiyonların, ancak dönüş türlerinin farklı olmasını istediğinizde ortaya çıkar. Çoğu dil aynı adlı iki yöntem arasında nasıl farklı ayrım yapılacağını bilmez. Bu noktada, dönüş türündeki farkı göstermek için jenerikleri kullanma, parametre arayüzünü değiştirme veya yöntemlerinizden birini yeniden adlandırma hakkında düşünmeniz gerekir. Bu gibi durumlarla başa çıkmak için basit ve net bir adlandırma şemasına karar vermezseniz, okunabilirlik büyük bir sorun haline gelebilir.

Sizin aşırı yöntemleri adlandırma GetSomething()ve GetSomethingEx()farklılıklar aralarındaki tek fark vardır dönüş türleri ise, özellikle sizin yöntemler arasında ne hakkında çok şey söylemek gitmiyor. Öte yandan, GetSomethingAsInt()ve GetSomethingAsString()yöntemler ne yaptığını hakkında biraz daha söylemek değil, kesinlikle bir aşırı ederken, do iki yöntem benzer şeyler olduğunu göstermektedir, ancak farklı türde değer. Yöntemleri adlandırabilmenin başka yolları olduğunu biliyorum, ancak noktayı açıklamak için bu kaba örneklerin yapması gerekiyor.

OPs örneğinde, yöntem parametreleri farklı olduğu için yeniden adlandırma kesinlikle gerekli değildir, ancak bir yöntemi daha spesifik olarak adlandırmak işleri biraz daha açık hale getirir. Sonunda, gerçekten kullanıcılarınıza sunmak istediğiniz arayüz türüne gelir. Aşırı yüklenmemeye karar vermek yalnızca kendi okunabilirlik algınıza dayanarak verilmemelidir. Aşırı yükleme yöntemleri, örneğin bir API arayüzünü basitleştirebilir ve bir geliştiricinin hatırlaması gerekebilecek yöntem sayısını azaltabilir, diğer yandan arayüzü, geliştiricinin hangi formu anlamak için yöntem belgelerini okumasını gerektiren bir dereceye kadar gizleyebilir. benzer ama açıklayıcı olarak adlandırılmış bir dizi yönteme sahip olmak, sadece amacına göre bir yöntem adı okumak daha açık hale getirebilir.


0

Yöntemler aynı şeyi döndürdüğü ve aynı sözleşmeyi takip ettiği sürece aşırı yüklemeyi tercih edin. Aşırı yükleme, arama kodunun gereksiz yere parametre tipine geçmesini engeller.

Arama işlevinin parametre olarak bir arama sorgusu aldığını ve çağrıdan önce ve / veya sonra başka işlemler gerçekleştirdiğini varsayalım find.

void tryToSellCars(String which) {
    /* grab an airhorn, inflatable tube guy... */
    List<Car> cars = find(which);
    /* expound virtues of each car in detail... */
}

Herhangi bir nedenden ötürü bu sorgunun türünü değiştirmek istiyorsanız (örneğin, basit bir kimlik dizesinden bir tür tam özellikli sorgu nesnesine), işlev işlevinde yalnızca işlev imzasını değiştirerek bu değişikliği yapabilirsiniz. sınıfınızda çağırdığı yöntemi değiştirmeden endişe etmeden yeni parametre türünü kabul etmek.

void tryToSellCar(CarQuery which) {
    /* grab airhorn, inflate tube guy... */
    List<Car> cars = find(which)
    /* expound virtues of each car in detail... */
}

Eğer uygularsanız findByIdve findByQueryObjectayrı ayrı, bu değişikliği yapmak için her çağrıyı avlamak zorunda kalacaktı. Örnekte, sadece bir kelimeyi değiştirdim ve işim bitti.


Bu yanıt, elbette, geçersiz bir parametre için derleme zamanı hatalarıyla aşırı yüklemeyi destekleyen bir dil kullandığınızı varsayar. JavaScript veya Ruby veya aşırı yüklemeyi yerel olarak desteklemeyen başka bir dil yazıyorsanız, findByFoodaha önce tür uyumsuzluklarını yakalamak için her zaman ayrıntılı kullanırdım.
sqykly
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.