Yöntem aşırı yüklemesi ne zaman uygundur?


10

Mevcut, oldukça büyük bir sistem üzerinde çalıştığımı varsayalım. myObjectSınıfın bir nesnesi var MyClass(örneğin uğruna, Java'da çalıştığımı varsayalım). myObjecta Collection, mesela a Listve diğer (önemsiz) objeleri içeren bir bileşimdir . Bu, maruz kalmamasını Listsağlamak için sadece oluştuğu yöntemleri çağırmaya hizmet eden temsilci yöntemleri içerir List(terminolojimi yanlış anladığım için üzgünüm).

Bunun Listbir List<String>neden olduğunu söyleyebiliriz, ancak bazı nedenlerden dolayı ana erişim yöntemi sınıf için bir maske yöntemidir SomeOtherClass. Eğer yeni bir değer çifti eklemek isteseydim List, SomeOtherClassçağrılmış bir cisim olurdu someObject. Ben çağırır myObject.insert(someObject)ve insertyöntemin içinde Stringiçine koymak için alacak bir sihir olurdu List<String>.

Diyelim ki sadece bir değerim var Stringve SomeOtherClasseklenecek nesne yok . insertYöntemi değiştiremediğim varsayılıyor çünkü bu sistemdeki her şeyi kıracak. O zaman insertyöntemi aşırı yüklemem gerekir mi? Yoksa SomeOtherClassher aramak istediğimde yeni bir nesne mi oluşturmalıyım insert?

Ben aşırı yük olsaydı, böyle bir şey olurdu sanırım ...

public void insert(String s) {
    ...
}

public void insert(SomeOtherObject obj) {
    this.insert(obj.magicStringMethod());
}

(Bu örnek, dün karşılaştığım aşırı yükleme ile ilgili benzer (biraz daha karmaşık) bir duruma dayanan yapmacık bir bulmaca. Belirsiz bir şey varsa genişleteceğim)

Burası bir yöntemi aşırı yüklemek için uygun bir yer olabilir mi? Değilse, ne zaman bir yöntemi aşırı yüklemeliyim?


Java'yı varsayarsak, bu sorunu çözmek için Generics'i kullandınız mı? Sanırım gerçekten sorduğum şey, String'in gerçekten neyi temsil ettiği? Gerçekten gerçek bir etki alanı nesnesinin bir temsili ise, bu sorunu çözmek için başka bir potansiyel yol daha vardır
Martijn Verburg

@MartijnVerburg Henüz bu aşamada yapmadım. Sadece stajyer olduğum için tasarım desenleri gibi şeylere hâlâ biraz yabancıyım ve henüz iyi tasarım uygulama alışkanlıklarım yok. İkinci sorunuza yanıt olarak, gerçek bir etki alanı nesnesinin temsilidir. magicStringMethod()benim örneğimde, benim durumumda, bir etki alanı nesnesi olan bir Stringtemsilini alır SomeOtherObject.
blahman

Mümkün olduğunda aşırı yüklenmeden uzak durmanızı öneririm. Bazen karışıklığa neden olur. Tasarım zamanında çağrılan yöntem hakkında emin olmak en iyisidir.
Şuna

Yanıtlar:


7

Farklı türleri desteklemek istediğinizde aşırı yüklenirsiniz:

public overload void MyMethod(int value)
{ 
}

public overload void MyMethod(bool value)
{
}

public overload void MyMethod(string value)
{
}

veya farklı parametre listelerini kullanarak aşamalı bir arayüzü desteklemek için:

public overload void MyOtherMethod()
{
    this.MyOtherMethod(DefaultValue);
}

public overload void MyOtherMethod(int value)
{
    this.MyOtherMethod(value, DefaultOtherValue);
}

public overload void MyOtherMethod(int value, bool otherValue)
{
    ...
}

Hatta biraz çılgınlaşabilir ve her iki farklı türü VE ilerici bir arayüzü destekleyebilirsiniz, ancak aşırı yüklenmiş yöntemler arasında davranış varyasyonları oluşturmaktan kaçınmanız gerektiğini unutmayın. Her aşırı yüklenmiş yöntem, aşırı yüklenmiş bir gruptaki diğerleriyle işlevsel olarak aynı olmalıdır, aksi takdirde davranışın nasıl, ne zaman ve neden değiştiği konusunda net olmayacaktır. İki işlevin tamamen farklı bir şey yapmasını istiyorsanız, bunları uygun şekilde adlandırmalısınız.


7

Her iki yöntemin de anlamsal olarak eşdeğer olması durumunda aşırı yüklemenin uygun olduğunu söyleyebilirim. Dukeofgaming'in örneklerinden çalmak için:

Bunlar uygun şekilde aşırı yüklenmiş:

public int sum(int a, int b){
    return a+b;
}

public double sum(double a, double b){
    return a+b;
}

Bunlar değil:

public int sum(int a, int b){
    return a+b;
}

public double sum(double a, double b){
    return a-b;
}

Bu aşırı bir örnektir (eğer onu yakalamadıysanız, son yöntem aslında eklemeler yerine çıkarır), ancak fikir, aynı ada sahip bir sınıfta birden çok yönteminiz varsa, tutarlı davranmaları gerektiğidir.

Örneğinizde, verilen bilgilerden eşdeğer görünmektedirler (biri diğerini çağırdığı için) ve onları aşırı yüklemenin makul olduğunu düşünürdüm. Yöntemin eklenmesi gerekip gerekmediğinden emin değilseniz ekibinizde daha kıdemli birine sormak zarar veremez, ancak eklediyseniz aynı adı kullanırdım (yani aşırı yüklerim).


1
Cevap için teşekkürler. Ben daha kıdemli birine sormak yaptı, ama kod biraz ilginç bir durumda olduğundan onların çözüm bir emin değildi, ama yine de uygulanan (aşırı yükleme değildi).
blahman

5

Esasen yöntemin parametrelerinin, yöntemin nasıl davranacağını belirlemesi.

Kısa bir örnek:

class Calc{
    //...
    public int sum(int a, int b){
        return a+b;
    }
    public double sum(double a, double b){
        return a+b;
    }
    //...
}

Yöntem toplamını (a, b) birkaç tamsayı geçerseniz, ilk çağrıyı çağırması gerektiğini bilir, çünkü yöntem çağrısı yöntem imzasıyla çakışır (yani, çift toplam (çift, çift), toplam yöntemi iki tamsayı).

Çağrının imzası mevcut uygulamalarla eşleşmelidir; bu nedenle, sum (string, string) çağrılmaya çalışılmadıkça, aşağıdakiler çalışmaz:

class Calc{
    //...
    public int sum(int a, int b){
        return a+b;
    }
    public double sum(double a, double b){
        return a+b;
    }
    public string sum(String a, String b){
        return "" + (Double.parseDouble(a) + Double.parseDouble(b));
    }
    //...
}

tl; dr: Sınıfın, aynı ada sahip bir yöntem verdiğiniz parametrelere göre doğru yöntemi kullanmasını sağlamak.

Devralınırken buna geçersiz kılma denir

Bu diğer senaryonun iyi bir örneği, bir sınıfı devralarak varsayılan davranışını değiştirmek istediğinizde ve özellikle bir yöntemde bazı algoritmaların her adımını uyguladığınız şablon yöntemi desenine benzer bir şey olduğunda .

Birbirinize arka arkaya class Robotçağıran fireAtTarget(Target target)... bir yöntem olduğunu hayal edin fireWeaponA(target); fireWeaponB(target); fireWeaponC(target);. Ayrıca, yalnızca Robot sınıfının nesnelerini ekleyebileceğiniz robot_army adlı bir koleksiyona sahip olmak istersiniz. Robot, fireWeaponX()yöntemlerinde varsayılan olarak makineli tüfekleri ateşler .

Sonra sahip olmak istiyorum class LazorRobotve class MissileRobotsen ?, baştan Robot uygulamak hayır, sadece LazorRobot ve MissileRobot devralır Robot var ve yok, aşırı Her fireWeaponX()kullanım lazorz veya füzelerin yöntemi ve tekrar uygulamanız gerek kalmadan, farklı silahlarla aynı davranış olacaktır yöntemlerin geri kalanı.

tl; dr: Yöntemin davranışının arabirimi bozmadan sınıfa bağlı olması (robot_army yalnızca Robot'u kabul eder, ancak Robot'u devralan sınıfları genişleterek kabul eder).


İlk örneğiniz bir geçersiz kılmadır . Bir yöntemin arabirimini koruduğunuzda ve bir torundan davranışı değiştirdiğinizde. Bunun anlamı, alternatif bir yöntem sunmayı düşünmemenizdir. Ancak ikinci örneğiniz aşırı yükleniyor. Niyetiniz ne zaman geçersiz kılmaya karşı ne zaman aşırı yükleneceğinin altını çizmekse, cevabınızda bunu daha açık hale getirmek isteyebilirsiniz, aksi takdirde tüm when inheritingbölüm muhtemelen gerekli değildir. :)
S.Robins

Derp, kafein beni bu kez elde etti = P, ikinci bölümü birinci, birinci bölümü ise genel ilgi için ikinci olarak bıraktı. Düzeltme için teşekkürler.
dukeofgaming

Eğer doğru cevap anlamak, bana diyelim arasındaki davranış farklılıkları anlaması sağlayacak parametrelerin bakarken sadece aşırı, olmalıdır sum(String, String)ve sum(int, int)?
blahman

@blahman farklı tipler, tipler karışımı kullanmak veya hatta ek parametreler eklemek istediğinizde aşırı yüklemeniz gerekir. Aşırı yükleme, param = value default sözdiziminin desteklenmediği varsayılan parametrelerle yöntemler oluşturmanın bir yolunu sunar . Ne demek istediğimi görmek için cevabımı görün.
S.Robins

1
@blahman BTW ve başka bir konuda, çok fazla parametreniz varsa ve bazıları isteğe bağlı olduğunda, bazen tüm varsayılan değerlere sahip tek bir nesne veya veri yapısı göndermek daha iyidir, böylece bu nesnenin veya verilerin özelliklerini değiştirirsiniz. yapısı. Bu şekilde, her seferinde tek bir parametre eklemek için aynı yöntemin 20 sürümünü yapmanız gerekmez.
dukeofgaming
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.