Saya perhatikan beberapa fungsi yang saya gunakan memiliki 6 atau lebih parameter, sedangkan di kebanyakan perpustakaan saya jarang menemukan fungsi yang membutuhkan lebih dari 3.
Seringkali banyak dari parameter tambahan ini adalah opsi biner untuk mengubah perilaku fungsi. Saya pikir beberapa dari beberapa fungsi parameter ini mungkin harus di refactored. Apakah ada pedoman untuk nomor berapa yang terlalu banyak?
functions
parameters
Darth Egregious
sumber
sumber
Jawaban:
Saya belum pernah melihat pedoman, tetapi dalam pengalaman saya fungsi yang membutuhkan lebih dari tiga atau empat parameter menunjukkan salah satu dari dua masalah:
Sulit untuk mengatakan apa yang Anda lihat tanpa informasi lebih lanjut. Kemungkinannya adalah refactoring yang perlu Anda lakukan adalah membagi fungsi menjadi fungsi yang lebih kecil yang dipanggil dari induk tergantung pada bendera yang saat ini sedang diteruskan ke fungsi.
Ada beberapa keuntungan baik yang bisa didapat dengan melakukan ini:
if
struktur yang memanggil banyak metode dengan nama deskriptif daripada struktur yang melakukan semuanya dalam satu metode.sumber
Menurut "Kode Bersih: Buku Pegangan Pengerjaan Perangkat Lunak Agile", nol adalah yang ideal, satu atau dua dapat diterima, tiga dalam kasus khusus dan empat atau lebih, tidak pernah!
Kata-kata penulis:
Dalam buku ini ada bab yang hanya berbicara tentang fungsi di mana parameternya besar dibahas, jadi saya pikir buku ini bisa menjadi pedoman yang baik tentang berapa banyak parameter yang Anda butuhkan.
Menurut pendapat pribadi saya, satu parameter lebih baik daripada tidak ada karena saya pikir lebih jelas apa yang sedang terjadi.
Sebagai contoh, menurut saya pilihan kedua lebih baik karena lebih jelas apa metode pengolahannya:
vs.
Tentang banyak parameter, ini bisa menjadi tanda bahwa beberapa variabel dapat dikelompokkan menjadi satu objek atau, dalam hal ini, banyak boolean dapat menyatakan bahwa fungsi / metode melakukan lebih dari satu hal, dan dalam hal ini, lebih baik refactoring masing-masing perilaku ini dalam fungsi yang berbeda.
sumber
String language = detectLanguage(someText);
. Dalam salah satu kasus Anda, Anda melewati jumlah argumen yang sama persis, kebetulan Anda telah membagi eksekusi fungsi menjadi dua karena bahasa yang buruk.Matrix.Create(input);
manainput
, katakanlah, .NETIEnumerable<SomeAppropriateType>
? Dengan begitu Anda juga tidak perlu kelebihan beban yang terpisah ketika Anda ingin membuat matriks yang menahan 10 elemen, bukan 9.Jika kelas domain dalam aplikasi dirancang dengan benar, jumlah parameter yang kita berikan ke fungsi akan dikurangi secara otomatis - karena kelas tahu cara melakukan pekerjaan mereka dan mereka memiliki cukup data untuk melakukan pekerjaan mereka.
Misalnya, Anda memiliki kelas manajer yang meminta kelas 3 untuk menyelesaikan tugas.
Jika Anda memodelkan dengan benar,
Ini sederhana.
Jika Anda tidak memiliki model yang benar, metodenya akan seperti ini
Model yang benar selalu mengurangi parameter fungsi antara pemanggilan metode karena fungsi yang benar didelegasikan ke kelas mereka sendiri (Tanggung jawab tunggal) dan mereka memiliki cukup data untuk melakukan pekerjaan mereka.
Setiap kali saya melihat jumlah parameter meningkat, saya memeriksa model saya untuk melihat apakah saya merancang model aplikasi saya dengan benar.
Ada beberapa pengecualian: Ketika saya perlu membuat objek transfer atau mengkonfigurasi objek, saya akan menggunakan pola pembangun untuk menghasilkan objek dibangun kecil terlebih dahulu sebelum membangun objek konfigurasi besar.
sumber
Satu aspek yang tidak dijawab oleh jawaban lain adalah kinerja.
Jika Anda memprogram dalam bahasa tingkat rendah yang cukup (C, C ++, assembly) sejumlah besar parameter bisa sangat merusak kinerja pada beberapa arsitektur, terutama jika fungsinya disebut sejumlah besar kali.
Ketika panggilan fungsi dibuat di ARM misalnya, empat argumen pertama ditempatkan dalam register
r0
untukr3
dan argumen yang tersisa harus didorong ke stack. Mempertahankan jumlah argumen di bawah lima dapat membuat perbedaan besar untuk fungsi kritis.Untuk fungsi yang dipanggil sangat sering, bahkan kenyataan bahwa program harus mengatur argumen sebelum setiap panggilan dapat mempengaruhi kinerja (
r0
untukr3
dapat ditimpa oleh fungsi yang dipanggil dan harus diganti sebelum panggilan berikutnya) jadi dalam hal itu argumen nol adalah yang terbaik.Memperbarui:
KjMag mengangkat topik menarik tentang inlining. Dalam beberapa hal, inlining akan memitigasi hal ini karena akan memungkinkan kompiler melakukan optimasi yang sama yang dapat Anda lakukan jika menulis dalam perakitan murni. Dengan kata lain, kompiler dapat melihat parameter dan variabel mana yang digunakan oleh fungsi yang dipanggil dan dapat mengoptimalkan penggunaan register sehingga tumpukan baca / tulis diminimalkan.
Ada beberapa masalah dengan inlining.
inline
diperlakukan sebagai wajib dalam semua kasus.inline
atau benar-benar memberi Anda kesalahan ketika mereka menemukannya.sumber
inline
.)Ketika daftar parameter bertambah menjadi lebih dari lima, pertimbangkan untuk mendefinisikan struktur atau objek "konteks".
Ini pada dasarnya hanya struktur yang menampung semua parameter opsional dengan beberapa pengaturan default yang masuk akal.
Dalam dunia prosedural C struktur sederhana akan dilakukan. Di Jawa, C ++ objek sederhana akan cukup. Jangan mengotak-atik getter atau setter karena satu-satunya tujuan objek adalah untuk memegang nilai "yang dapat diatur" publik.
sumber
Tidak, tidak ada pedoman standar
Tetapi ada beberapa teknik yang bisa membuat fungsi dengan banyak parameter lebih tertahankan.
Anda bisa menggunakan parameter list-if-args (args *) atau parameter dictionary-of-args (kwargs
**
)Misalnya, dengan python:
Output:
Atau Anda bisa menggunakan sintaks definisi objek objek
Misalnya, inilah panggilan JavaScript jQuery untuk meluncurkan permintaan GET AJAX:
Jika Anda melihat kelas ajax jQuery ada banyak (sekitar 30) lebih banyak properti yang dapat diatur; sebagian besar karena komunikasi ajax sangat kompleks. Untungnya, sintaksis objek literal membuat hidup mudah.
C # intellisense menyediakan dokumentasi parameter yang aktif sehingga tidak jarang melihat pengaturan metode overload yang sangat kompleks.
Bahasa yang diketik secara dinamis seperti python / javascript tidak memiliki kemampuan seperti itu, jadi jauh lebih umum untuk melihat argumen kata kunci dan definisi literal objek.
Saya lebih suka definisi objek literal ( bahkan dalam C # ) untuk mengelola metode yang kompleks karena Anda dapat secara eksplisit melihat properti yang sedang diatur ketika objek dibuat. Anda harus melakukan sedikit lebih banyak pekerjaan untuk menangani argumen default tetapi dalam jangka panjang kode Anda akan jauh lebih mudah dibaca. Dengan definisi literal objek, Anda dapat memecah ketergantungan Anda pada dokumentasi untuk memahami apa yang dilakukan kode Anda pada pandangan pertama.
IMHO, metode kelebihan beban sangat berlebihan.
Catatan: Jika saya ingat kontrol akses hanya baca yang benar harus bekerja untuk konstruktor literal objek dalam C #. Mereka pada dasarnya bekerja sama dengan menyetel properti di konstruktor.
Jika Anda belum pernah menulis kode non-sepele dalam bahasa yang diketik secara dinamis (python) dan / atau fungsional / prototipe javaScript, saya sangat menyarankan untuk mencobanya. Ini bisa menjadi pengalaman yang mencerahkan.
Pertama-tama bisa menakutkan untuk mematahkan ketergantungan Anda pada parameter untuk akhir semua, semua pendekatan untuk fungsi / metode inisialisasi tetapi Anda akan belajar untuk melakukan lebih banyak lagi dengan kode Anda tanpa harus menambahkan kompleksitas yang tidak perlu.
Memperbarui:
Saya mungkin harus memberikan contoh untuk menunjukkan penggunaan dalam bahasa yang diketik secara statis, tetapi saat ini saya tidak berpikir dalam konteks yang diketik secara statis. Pada dasarnya, saya telah melakukan terlalu banyak pekerjaan dalam konteks yang diketik secara dinamis untuk tiba-tiba kembali.
Apa yang saya lakukan tahu adalah objek sintaks definisi literal benar-benar mungkin dalam bahasa statis diketik (setidaknya dalam C # dan Java) karena saya telah menggunakan mereka sebelumnya. Dalam bahasa yang diketik secara statis mereka disebut 'Inisialisasi Objek'. Berikut adalah beberapa tautan untuk menunjukkan penggunaannya di Java dan C # .
sumber
Secara pribadi, lebih dari 2 adalah tempat pemicu alarm bau kode saya. Ketika Anda menganggap fungsi sebagai operasi (yaitu, terjemahan dari input ke output), tidak biasa bahwa lebih dari 2 parameter digunakan dalam operasi. Prosedur (yang merupakan serangkaian langkah untuk mencapai tujuan) akan mengambil lebih banyak input dan kadang-kadang merupakan pendekatan terbaik, tetapi dalam kebanyakan bahasa dewasa ini seharusnya tidak menjadi norma.
Tetapi sekali lagi, itu adalah pedoman daripada aturan. Saya sering memiliki fungsi yang mengambil lebih dari dua parameter karena keadaan yang tidak biasa atau kemudahan penggunaan.
sumber
Sangat mirip dengan yang dikatakan Evan Plaice, saya penggemar berat hanya lewat array asosiatif (atau struktur data yang sebanding dengan bahasa Anda) ke dalam fungsi bila memungkinkan.
Jadi, alih-alih (misalnya) ini:
Pergi untuk:
Wordpress melakukan banyak hal dengan cara ini, dan saya pikir itu berfungsi dengan baik. (Meskipun kode contoh saya di atas adalah imajiner, dan itu sendiri bukan contoh dari Wordpress.)
Teknik ini memungkinkan Anda untuk mengirim banyak data ke dalam fungsi Anda dengan mudah, namun membebaskan Anda dari harus mengingat urutan di mana masing-masing harus dilewati.
Anda juga akan menghargai teknik ini ketika tiba saatnya untuk melakukan refactor - alih-alih harus berpotensi mengubah urutan argumen fungsi (seperti ketika Anda menyadari Anda harus melewati Yet Another Argument), Anda tidak perlu mengubah parameter fungsi Anda daftar sama sekali.
Ini tidak hanya membuat Anda tidak perlu menulis ulang definisi fungsi Anda - tetapi juga membuat Anda tidak perlu mengubah urutan argumen setiap kali fungsi dipanggil. Itu kemenangan besar.
sumber
Jawaban sebelumnya menyebutkan seorang penulis andal yang menyatakan bahwa semakin sedikit parameter fungsi Anda, semakin baik yang Anda lakukan. Jawabannya tidak menjelaskan mengapa tetapi buku-buku menjelaskannya, dan berikut adalah dua alasan paling meyakinkan mengapa Anda perlu mengadopsi filosofi ini dan yang secara pribadi saya setujui:
Parameter termasuk tingkat abstraksi yang berbeda dari fungsi. Ini berarti pembaca kode Anda harus berpikir tentang sifat dan tujuan dari parameter fungsi Anda: pemikiran ini "tingkat lebih rendah" dari pada nama dan tujuan fungsi yang sesuai.
Alasan kedua untuk memiliki parameter sesedikit mungkin untuk suatu fungsi adalah pengujian: misalnya, jika Anda memiliki fungsi dengan 10 parameter, pikirkan berapa banyak kombinasi parameter yang harus Anda tutupi semua kotak uji, misalnya, sebuah unit uji. Parameter lebih sedikit = lebih sedikit tes.
sumber
Untuk memberikan lebih banyak konteks di sekitar saran untuk jumlah ideal argumen fungsi menjadi nol dalam "Kode Bersih: Sebuah Buku Pegangan Pengerjaan Perangkat Lunak Agile Robert Martin", penulis mengatakan yang berikut sebagai salah satu poinnya:
Untuk
includeSetupPage()
contohnya di atas, berikut adalah potongan kecil dari "kode bersih" -nya yang telah direaktur ulang di akhir bab ini:"Sekolah pemikiran" penulis berpendapat untuk kelas kecil, jumlah argumen fungsi yang rendah (idealnya 0), dan fungsi yang sangat kecil. Walaupun saya juga tidak sepenuhnya setuju dengannya, saya merasa hal itu menggugah pikiran dan saya merasa bahwa ide nol argumen berfungsi sebagai ideal dapat dipertimbangkan. Juga, perhatikan bahwa bahkan potongan kode kecilnya di atas memiliki fungsi argumen non-nol juga, jadi saya pikir itu tergantung pada konteksnya.
(Dan seperti yang telah ditunjukkan orang lain, dia juga berpendapat bahwa lebih banyak argumen mempersulit dari sudut pandang pengujian. Tapi di sini saya terutama ingin menyoroti contoh di atas dan alasannya untuk argumen fungsi nol.)
sumber
Idealnya nol. Satu atau dua ok, tiga dalam kasus tertentu.
Empat atau lebih biasanya merupakan praktik yang buruk.
Selain prinsip-prinsip tanggung jawab tunggal yang telah dicatat orang lain, Anda juga dapat memikirkannya dari sudut pandang pengujian dan debugging.
Jika ada satu parameter, mengetahui nilai-nilai itu, mengujinya dan menemukan kesalahan dengan mereka 'relatif mudah karena hanya ada satu faktor. Ketika Anda meningkatkan faktor-faktornya, kompleksitas total meningkat dengan cepat. Untuk contoh abstrak:
Pertimbangkan program 'apa yang akan dipakai dalam cuaca ini'. Pertimbangkan apa yang bisa dilakukan dengan satu input - suhu. Seperti yang dapat Anda bayangkan, hasil pakaian yang dikenakan cukup sederhana berdasarkan satu faktor itu. Sekarang perhatikan apa yang mungkin / bisa / harus dilakukan program jika benar-benar melewati suhu, kelembaban, titik embun, curah hujan, dll. Sekarang bayangkan betapa sulitnya melakukan debug jika memberikan jawaban yang 'salah' untuk sesuatu.
sumber