Kapan metode overloading tepat?

10

Misalkan saya sedang mengerjakan sistem yang sudah ada dan cukup besar. Saya punya objek, myObjectkelas MyClass(demi contoh, misalkan saya bekerja di Jawa). myObjectadalah komposisi yang mengandung Collection, katakanlah, Listdan benda lain yang (saya pikir) tidak relevan. Ini berisi metode delegasi yang hanya berfungsi untuk memanggil metode Listitu terdiri dari, untuk memastikan Listitu tidak terbuka (maaf jika saya salah terminologi saya).

Katakanlah ini Listadalah List<String>tetapi, untuk beberapa alasan, metode akses utama adalah metode topeng untuk kelas SomeOtherClass. Jika saya ingin memasukkan pasangan nilai baru ke saya List, maka saya akan memiliki objek yang SomeOtherClassdipanggil someObject. Saya akan menelepon myObject.insert(someObject)dan di dalam insertmetode akan ada beberapa sihir yang akan mengambil Stringuntuk dimasukkan ke dalam List<String>.

Misalkan sekarang saya hanya punya Stringnilai, dan tidak ada SomeOtherClassobjek untuk dimasukkan. Dengan asumsi saya tidak dapat memodifikasi insertmetode ini karena akan merusak semua yang ada di sistem ini. Lalu haruskah saya membebani insertmetode ini? Atau haruskah saya membuat objek baru SomeOtherClasssetiap kali saya ingin menelepon insert?

Saya kira jika saya membebani secara berlebihan, itu akan terlihat seperti ini ...

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

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

(Contoh ini adalah teka-teki yang dibuat berdasarkan situasi yang serupa (sedikit lebih kompleks) mengenai kelebihan muatan yang saya temui kemarin. Saya akan memperluasnya jika ada sesuatu yang tidak jelas)

Apakah ini tempat yang tepat untuk membebani suatu metode? Jika tidak, kapan saya harus membebani metode?

blahman
sumber
Dengan asumsi Java, sudahkah Anda melihat menggunakan Generics untuk menyelesaikan masalah ini? Saya kira apa yang sebenarnya saya tanyakan adalah apa yang benar-benar mewakili String? Jika itu sebenarnya benar-benar representasi dari objek domain yang sebenarnya maka ada cara potensial lain untuk menyelesaikan masalah ini
Martijn Verburg
@ MartijnVerburg, saya belum, pada tahap ini. Karena saya hanya pekerja magang, saya masih sedikit terbiasa dengan hal-hal seperti pola desain dan saya belum memiliki kebiasaan praktik desain yang baik. Sebagai jawaban untuk pertanyaan kedua Anda, ini adalah representasi dari objek domain aktual. magicStringMethod()dalam contoh saya akan, dalam kasus saya, mendapatkan Stringrepresentasi SomeOtherObjectyang merupakan objek domain.
blahman
Saya sarankan Anda tinggal jauh dari kelebihan beban saat Anda bisa. Terkadang hal itu menyebabkan kebingungan. Yang terbaik adalah memastikan tentang metode yang disebut pada waktu desain. Lihat ini: programmers.stackexchange.com/questions/132369/…
NoChance

Jawaban:

7

Anda kelebihan ketika Anda ingin mendukung berbagai jenis:

public overload void MyMethod(int value)
{ 
}

public overload void MyMethod(bool value)
{
}

public overload void MyMethod(string value)
{
}

atau untuk mendukung antarmuka progresif menggunakan daftar parameter yang berbeda:

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)
{
    ...
}

Anda bahkan mungkin menjadi sedikit gila dan mendukung kedua jenis DAN antarmuka progresif, tetapi Anda harus ingat bahwa Anda perlu menghindari membuat variasi dalam perilaku antara metode kelebihan beban. Setiap metode kelebihan beban harus secara fungsional sama dengan yang lain dalam kelompok kelebihan beban, jika tidak akan tidak jelas bagaimana, kapan atau mengapa perilaku sedang bervariasi. Jika Anda ingin dua fungsi melakukan sesuatu yang sama sekali berbeda, maka Anda harus menamainya sesuai.

S.Robins
sumber
7

Saya akan mengatakan bahwa overloading tepat ketika kedua metode tersebut secara semantik setara. Untuk mencuri dari contoh-contoh dukeofgaming:

Ini kelebihan beban secara tepat:

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

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

Ini bukan:

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

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

Itu adalah contoh ekstrem (jika Anda tidak menangkapnya, metode terakhir sebenarnya mengurangi bukannya menambahkan), tetapi idenya adalah bahwa jika Anda memiliki beberapa metode di kelas dengan nama yang sama mereka harus berperilaku secara konsisten.

Dalam contoh Anda, dari informasi yang diberikan mereka tampak setara (karena yang satu memanggil yang lain) dan saya pikir masuk akal untuk membebani mereka. Tidak ada salahnya untuk bertanya kepada seseorang yang lebih senior di tim Anda jika Anda tidak yakin apakah metode ini harus ditambahkan tetapi jika Anda menambahkannya, saya akan menggunakan nama yang sama (yaitu saya akan membebani secara berlebihan).

Gyan alias Gary Buyn
sumber
1
Terima kasih atas jawabannya. Saya memang meminta seseorang yang lebih senior, tetapi karena kode ini dalam keadaan yang agak menarik solusi mereka adalah salah satu yang saya tidak yakin, tetapi tetap diimplementasikan (bukan overloading).
blahman
5

Pada dasarnya untuk memiliki parameter metode menentukan bagaimana metode akan berperilaku.

Contoh singkatnya adalah:

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

Jika Anda melewatkan jumlah metode (a, b) beberapa bilangan bulat, ia tahu bahwa ia harus memanggil implementasi pertama, karena pemanggilan metode bertepatan dengan tanda tangan metode (yaitu, jumlah ganda (ganda, ganda) tidak akan berfungsi jika Anda memberikan metode penjumlahan dua bilangan bulat).

Tanda tangan panggilan harus sesuai dengan implementasi yang tersedia, jadi mencoba memanggil jumlah (string, string) tidak akan berfungsi kecuali Anda memiliki ini:

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: Agar kelas menangani metode yang benar sesuai dengan parameter apa pun yang Anda berikan metode dengan nama yang sama.

Saat mewarisi, itu disebut mengesampingkan

Contoh yang baik dari skenario lain ini adalah ketika Anda ingin mengubah perilaku default suatu kelas dengan mewarisinya, dan terutama ketika Anda memiliki sesuatu yang mirip dengan pola metode templat , di mana Anda memiliki setiap langkah dari beberapa algoritma yang diimplementasikan dalam suatu metode.

Bayangkan Anda memiliki class Robotdan metode yang disebut fireAtTarget(Target target)... yang memanggil fireWeaponA(target); fireWeaponB(target); fireWeaponC(target);satu demi satu. Anda juga ingin memiliki koleksi bernama robot_army yang hanya dapat Anda tambahkan objek dari Robot kelas. Robot menembakkan senapan mesin secara default dalam fireWeaponX()metodenya.

Maka Anda ingin memiliki class LazorRobotdan class MissileRobot, apakah Anda menerapkan Robot sekali lagi?, Tidak, hanya perlu LazorRobot dan MissileRobot mewarisi Robot, dan membebani setiap fireWeaponX()metode untuk menggunakan lazorz atau rudal dan Anda akan memiliki perilaku yang sama dengan senjata yang berbeda, tanpa harus mengimplementasikan ulang sisa metode.

tl; dr: Agar perilaku metode bergantung pada kelas tanpa merusak antarmuka (robot_army hanya menerima Robot, tetapi menerima dengan ekstensi setiap kelas yang mewarisi Robot).

dukeofgaming
sumber
Contoh pertama Anda adalah penggantian . Saat Anda mempertahankan antarmuka metode, namun ubah perilaku dalam turunan. Implikasinya adalah Anda tidak bermaksud menawarkan metode alternatif. Namun contoh kedua Anda kelebihan beban dengan benar. Jika niat Anda adalah untuk menyoroti kapan harus mengganti vs kapan harus kelebihan beban, Anda mungkin ingin membuat ini lebih jelas dalam jawaban Anda, jika tidak seluruh when inheritingbagian mungkin tidak diperlukan. :)
S.Robins
Derp, kafein membuat saya kali ini = P, meninggalkan bagian kedua sebagai bagian pertama dan yang kedua sebagai bagian untuk kepentingan umum. Terima kasih atas koreksinya.
dukeofgaming
Jika saya memahami jawaban Anda dengan benar, saya harus kelebihan beban hanya ketika melihat parameter akan memungkinkan saya untuk menyimpulkan perbedaan perilaku antara, katakanlah, sum(String, String)dan sum(int, int)?
blahman
@manlah, Anda harus kelebihan beban ketika Anda ingin menggunakan berbagai jenis, campuran jenis, atau bahkan untuk menambahkan parameter tambahan. Overloading menyediakan cara untuk membuat metode dengan parameter default di mana param = nilai sintaks default tidak didukung. Lihat jawaban saya untuk melihat apa yang saya maksud.
S.Robins
1
@ Blahman BTW dan pada subjek lain, ketika Anda memiliki terlalu banyak parameter dan beberapa di antaranya opsional kadang-kadang lebih baik mengirim satu objek atau struktur data yang memiliki semua nilai default, sehingga Anda mengubah atribut objek atau data tersebut struktur. Dengan begitu Anda tidak perlu membuat 20 versi dari metode yang sama hanya untuk menambahkan parameter tunggal setiap kali.
dukeofgaming