Adakah pedoman tentang berapa banyak parameter yang harus diterima fungsi?

114

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?

Darth Egregious
sumber
4
@Minus: Idenya adalah Anda ingin menjaga kelas Anda tetap fokus. Kelas terfokus biasanya tidak memiliki banyak dependensi / atribut sehingga Anda akan memiliki lebih sedikit parameter untuk konstruktor. Beberapa kata buzz yang dilontarkan orang pada saat ini adalah kohesi tinggi dan prinsip tanggung jawab tunggal . Jika Anda merasa ini tidak dilanggar dan masih membutuhkan banyak param, pertimbangkan untuk menggunakan pola Builder.
c_maker
2
Tentunya jangan ikuti contoh MPI_Sendrecv () , yang membutuhkan 12 parameter!
chrisaycock
6
Proyek yang sedang saya kerjakan menggunakan kerangka kerja tertentu, di mana metode dengan 10+ parameter adalah hal biasa. Saya memanggil satu metode tertentu dengan 27 parameter di beberapa tempat. Setiap kali saya melihatnya, saya mati sedikit di dalam.
pelaku
3
Jangan pernah menambahkan sakelar boolean untuk mengubah perilaku fungsi. Pisahkan fungsi sebagai gantinya. Pecah perilaku umum menjadi fungsi baru.
kevin cline
2
@Minus Apa? Hanya 10 parameter? Itu bukan apa-apa, lebih banyak dibutuhkan . : D
maaartinus

Jawaban:

106

Saya belum pernah melihat pedoman, tetapi dalam pengalaman saya fungsi yang membutuhkan lebih dari tiga atau empat parameter menunjukkan salah satu dari dua masalah:

  1. Fungsi ini melakukan terlalu banyak. Ini harus dibagi menjadi beberapa fungsi yang lebih kecil, masing-masing memiliki set parameter yang lebih kecil.
  2. Ada benda lain yang bersembunyi di sana. Anda mungkin perlu membuat objek atau struktur data lain yang menyertakan parameter ini. Lihat artikel ini pada pola Parameter Object untuk informasi lebih lanjut.

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:

  • Itu membuat kode Anda lebih mudah dibaca. Saya pribadi merasa jauh lebih mudah untuk membaca "daftar aturan" yang terdiri dari ifstruktur yang memanggil banyak metode dengan nama deskriptif daripada struktur yang melakukan semuanya dalam satu metode.
  • Ini lebih mudah dites unit. Anda telah membagi masalah Anda menjadi beberapa tugas kecil yang secara individual sangat sederhana. Pengumpulan tes unit kemudian akan terdiri dari suite tes perilaku yang memeriksa jalur melalui metode master dan koleksi tes yang lebih kecil untuk setiap prosedur individu.
Michael K.
sumber
5
Parameter abstraksi telah berubah menjadi pola desain? Apa yang terjadi jika Anda memiliki 3 kelas parameter. Apakah Anda menambahkan 9 kelebihan metode lagi untuk menangani berbagai kombinasi parameter yang mungkin? Itu terdengar seperti masalah deklarasi parameter O (n ^ 2) yang tidak menyenangkan. Oh, tunggu, Anda hanya dapat mewarisi 1 kelas di Java / C # sehingga akan membutuhkan lebih banyak biolerplate (mungkin beberapa lagi subkelas) untuk membuatnya bekerja dalam praktik. Maaf, saya tidak yakin. Mengabaikan pendekatan yang lebih ekspresif yang dapat ditawarkan oleh bahasa demi kompleksitas hanya terasa salah.
Evan Plaice
Kecuali Anda menggunakan pola Obyek Pola untuk mengemas variabel dalam instance objek dan meneruskannya sebagai parameter. Itu bekerja untuk pengemasan tetapi mungkin tergoda untuk membuat kelas variabel yang berbeda hanya untuk kenyamanan menyederhanakan definisi metode.
Evan Plaice
@ EvanPlaice Saya tidak mengatakan bahwa Anda harus menggunakan pola itu setiap kali Anda memiliki lebih dari satu parameter - Anda benar bahwa itu menjadi lebih buruk daripada daftar pertama. Mungkin ada kasus di mana Anda benar-benar membutuhkan sejumlah besar parameter dan tidak berfungsi untuk membungkusnya dalam suatu objek. Saya belum pernah menemukan kasus dalam pengembangan usaha yang tidak jatuh ke dalam salah satu dari dua ember yang saya sebutkan dalam jawaban saya - itu tidak mengatakan bahwa tidak ada satu pun.
Michael K
@MichaelK Jika Anda belum pernah menggunakannya, coba googling 'inisialisasi objek'. Ini adalah pendekatan baru yang sangat mengurangi boilerplate definisi. Secara teori, Anda bisa menghilangkan konstruktor kelas, parameter, dan kelebihan semua dalam satu kesempatan. Namun dalam praktiknya, biasanya baik untuk mempertahankan satu konstruktor bersama dan mengandalkan sintaks 'penginisialisasi objek' untuk sisa properti tidak jelas / niche. IMHO, ini adalah yang terdekat dengan ekspresi bahasa yang diketik secara dinamis dalam bahasa yang diketik secara statis.
Evan Plaice
@Evain Plaice: Sejak kapan bahasa yang diketik secara dinamis ekspresif?
ThomasX
41

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:

Jumlah argumen ideal untuk suatu fungsi adalah nol (niladik). Berikutnya adalah satu (monadik), diikuti oleh dua (diad). Tiga argumen (triadik) harus dihindari jika memungkinkan. Lebih dari tiga (polyadic) membutuhkan pembenaran yang sangat khusus — dan karenanya tidak seharusnya digunakan.

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:

LangDetector detector = new LangDetector(someText);
//lots of lines
String language = detector.detectLanguage();

vs.

LangDetector detector = new LangDetector();
//lots of lines
String language = detector.detectLanguage(someText);

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.

Renato Dinhani
sumber
8
"Tiga dalam kasus khusus dan empat atau lebih, tidak pernah!" BS. Bagaimana dengan Matrix.Create (x1, x2, x3, x4, x5, x6, x7, x8, x9); ?
Lukasz Madon
71
Nol ideal? Bagaimana sih fungsi mendapatkan informasi? Global / instance / static / variabel apa pun? YUCK.
Peter C
9
Itu contoh yang buruk. Jawabannya jelas: 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.
Matthieu M.
8
@ lukas, dalam bahasa yang mendukung konstruksi mewah seperti array atau daftar (terkesiap!), bagaimana dengan di Matrix.Create(input);mana input, katakanlah, .NET IEnumerable<SomeAppropriateType>? Dengan begitu Anda juga tidak perlu kelebihan beban yang terpisah ketika Anda ingin membuat matriks yang menahan 10 elemen, bukan 9.
CVn
9
Nol argumen sebagai "ideal" adalah tempayan dan satu alasan saya pikir Kode Bersih adalah cara berlebihan.
user949300
24

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,

3rdGradeClass.finishHomework(int lessonId) {
    result = students.assignHomework(lessonId, dueDate);
    teacher.verifyHomeWork(result);
}

Ini sederhana.

Jika Anda tidak memiliki model yang benar, metodenya akan seperti ini

Manager.finishHomework(grade, students, lessonId, teacher, ...) {
    // This is not good.
}

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.

java_mouse
sumber
16

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 r0untuk r3dan 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 ( r0untuk r3dapat 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.

  1. Inlining menyebabkan tumbuh biner dikompilasi karena kode yang sama diduplikasi dalam bentuk biner jika dipanggil dari beberapa tempat. Ini merugikan ketika menyangkut penggunaan I-cache.
  2. Compiler biasanya hanya memungkinkan penyatuan hingga level tertentu (3 langkah IIRC?). Bayangkan memanggil fungsi inline dari fungsi inline dari fungsi inline. Pertumbuhan biner akan meledak jika inlinediperlakukan sebagai wajib dalam semua kasus.
  3. Ada banyak kompiler yang akan sepenuhnya mengabaikan inlineatau benar-benar memberi Anda kesalahan ketika mereka menemukannya.
Leo
sumber
Apakah melewati sejumlah besar parameter baik atau buruk dari perspektif kinerja tergantung pada alternatifnya. Jika suatu metode membutuhkan selusin informasi, dan seseorang akan memanggilnya ratusan kali dengan nilai yang sama untuk sebelas di antaranya, meminta metode mengambil array bisa lebih cepat daripada mengambil parameter selusin. Di sisi lain, jika setiap panggilan akan membutuhkan satu set unik dari dua belas nilai, membuat dan mengisi array untuk setiap panggilan dapat dengan mudah lebih lambat daripada hanya meneruskan nilai secara langsung.
supercat
Tidakkah inlining menyelesaikan masalah ini?
KjMag
@ KjMag: Ya, sampai tingkat tertentu. Tetapi ada banyak gotcha tergantung pada kompiler. Fungsi biasanya hanya akan digarisbawahi hingga tingkat tertentu (jika Anda memanggil fungsi inline yang memanggil fungsi inline yang memanggil fungsi inline ....). Jika fungsinya besar dan dipanggil dari banyak tempat, membuat garis di mana-mana membuat biner lebih besar yang bisa berarti lebih banyak kehilangan dalam cache-I. Jadi inlining bisa membantu, tapi itu bukan peluru perak. (Belum lagi ada beberapa kompiler tertanam lama yang tidak mendukung inline.)
Leo
7

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.

James Anderson
sumber
Saya setuju, objek konteks dapat berubah menjadi sangat berguna ketika struktur parameter fungsi mulai menjadi agak rumit. Baru-baru ini saya membuat blog tentang menggunakan objek konteks dengan pola seperti pengunjung
Lukas Eder
5

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:

// Example definition
def example_function(normalParam, args*, kwargs**):
  for i in args:
    print 'args' + i + ': ' + args[i] 
  for key in kwargs:
    print 'keyword: %s: %s' % (key, kwargs[key])
  somevar = kwargs.get('somevar','found')
  missingvar = kwargs.get('somevar','missing')
  print somevar
  print missingvar

// Example usage

    example_function('normal parameter', 'args1', args2, 
                      somevar='value', missingvar='novalue')

Output:

args1
args2
somevar:value
someothervar:novalue
value
missing

Atau Anda bisa menggunakan sintaks definisi objek objek

Misalnya, inilah panggilan JavaScript jQuery untuk meluncurkan permintaan GET AJAX:

$.ajax({
  type: 'GET',
  url: 'http://someurl.com/feed',
  data: data,
  success: success(),
  error: error(),
  complete: complete(),
  dataType: 'jsonp'
});

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 # .

Evan Plaice
sumber
3
Saya tidak yakin saya suka metode ini, terutama karena Anda kehilangan nilai mendokumentasikan diri parameter individu. Untuk daftar item sejenis, ini masuk akal (misalnya metode yang mengambil daftar string dan menyatukannya) tetapi untuk parameter arbitrer yang disetel ini lebih buruk daripada pemanggilan metode panjang.
Michael K
@MichaelK Lihatlah lagi inisialisasi objek. Mereka memungkinkan Anda untuk mendefinisikan properti secara eksplisit sebagai lawan dari bagaimana mereka didefinisikan secara implisit dalam metode / parameter fungsi tradisional. Baca ini, msdn.microsoft.com/en-us/library/bb397680.aspx , untuk melihat apa yang saya maksud.
Evan Plaice
3
Membuat tipe baru hanya untuk menangani daftar parameter terdengar persis seperti definisi kompleksitas yang tidak perlu ... Tentu, bahasa dinamis memungkinkan Anda menghindarinya tetapi kemudian Anda mendapatkan satu bola parameter goo. Bagaimanapun, ini tidak menjawab pertanyaan yang diajukan.
Telastyn
@ Telastyn Apa yang kamu bicarakan? Tidak ada tipe baru yang dibuat, Anda mendeklarasikan properti secara langsung menggunakan sintaks literal objek. Ini seperti mendefinisikan objek anonim tetapi metode menafsirkannya sebagai kunci = pengelompokan parameter nilai. Apa yang Anda lihat adalah metode instantiation (bukan objek enkapsulasi parameter). Jika daging sapi Anda menggunakan kemasan parameter, lihat pola Objek Parameter yang disebutkan dalam salah satu pertanyaan lain karena itulah yang sebenarnya.
Evan Plaice
@ EvanPlaice - Kecuali bahwa bahasa pemrograman statis oleh-dan-besar memerlukan jenis yang dinyatakan (sering baru) untuk memungkinkan pola Obyek Parameter.
Telastyn
3

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.

Telastyn
sumber
2

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:

<?php

createBlogPost('the title', 'the summary', 'the author', 'the date of publication, 'the keywords', 'the category', 'etc');

?>

Pergi untuk:

<?php

// create a hash of post data
$post_data = array(
  'title'    => 'the title',
  'summary'  => 'the summary',
  'author'   => 'the author',
  'pubdate'  => 'the publication date',
  'keywords' => 'the keywords',
  'category' => 'the category',
  'etc'      => 'etc',
);

// and pass it to the appropriate function
createBlogPost($post_data);

?>

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.

Chris Allen Lane
sumber
Melihat ini diposting menyoroti manfaat lain dari pendekatan pass-a-hash: perhatikan bahwa contoh kode pertama saya begitu lama menghasilkan scrollbar, sedangkan yang kedua pas bersih pada halaman. Hal yang sama kemungkinan akan berlaku di editor kode Anda.
Chris Allen Lane
0

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.

Billal Begueradj
sumber
0

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:

Argumennya sulit. Mereka mengambil banyak kekuatan konseptual. Itu sebabnya saya menyingkirkan hampir semuanya dari contoh. Pertimbangkan, misalnya, StringBufferdalam contoh. Kita bisa mengedarkannya sebagai argumen daripada menjadikannya sebagai variabel instan, tetapi kemudian pembaca kita harus menafsirkannya setiap kali mereka melihatnya. Saat Anda membaca cerita yang diceritakan oleh modul, includeSetupPage() lebih mudah dipahami daripada includeSetupPageInto(newPageContent). Argumennya berada pada tingkat abstraksi yang berbeda yang nama fungsinya dan memaksa Anda untuk mengetahui detail (dengan kata lain, StringBuffer) yang tidak terlalu penting pada saat itu.

Untuk includeSetupPage()contohnya di atas, berikut adalah potongan kecil dari "kode bersih" -nya yang telah direaktur ulang di akhir bab ini:

// *** NOTE: Commments are mine, not the author's ***
//
// Java example
public class SetupTeardownIncluder {
    private StringBuffer newPageContent;

    // [...] (skipped over 4 other instance variables and many very small functions)

    // this is the zero-argument function in the example,
    // which calls a method that eventually uses the StringBuffer instance variable
    private void includeSetupPage() throws Exception {
        include("SetUp", "-setup");
    }

    private void include(String pageName, String arg) throws Exception {
        WikiPage inheritedPage = findInheritedPage(pageName);
        if (inheritedPage != null) {
            String pagePathName = getPathNameForPage(inheritedPage);
            buildIncludeDirective(pagePathName, arg);
        }
    }

    private void buildIncludeDirective(String pagePathName, String arg) {
        newPageContent
            .append("\n!include ")
            .append(arg)
            .append(" .")
            .append(pagePathName)
            .append("\n");
    }
}

"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.)

nak
sumber
-2

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.

Michael Durrant
sumber
12
Jika suatu fungsi memiliki parameter nol, itu baik mengembalikan nilai konstan (berguna dalam beberapa keadaan, tetapi agak membatasi) atau menggunakan beberapa keadaan tersembunyi yang akan lebih baik dibuat eksplisit. (Dalam pemanggilan metode OO, objek konteks cukup eksplisit sehingga tidak menyebabkan masalah.)
Donal Fellows
4
-1 karena tidak mengutip sumbernya
Joshua Drake
Apakah Anda serius mengatakan bahwa idealnya semua fungsi tidak akan mengambil parameter? Atau apakah ini hiperbola?
GreenAsJade
1
Lihat argumen Paman Bob di: informit.com/articles/article.aspx?p=1375308 dan perhatikan bahwa di bagian bawah ia mengatakan "Fungsi harus memiliki sejumlah kecil argumen. Tidak ada argumen yang terbaik, diikuti oleh satu, dua, dan tiga . Lebih dari tiga sangat dipertanyakan dan harus dihindari dengan prasangka. "
Michael Durrant
Saya telah memberikan sumbernya. Lucu tidak ada komentar sejak itu. Saya juga mencoba menjawab bagian 'pedoman' karena banyak orang sekarang menganggap Paman Bob dan Kode Bersih sebagai pedoman. Menarik bahwa jawaban teratas sangat tinggi (saat ini) mengatakan tidak mengetahui adanya pedoman. Paman Bob tidak berniat untuk bersikap otoritatif tetapi itu memang benar dan jawaban ini setidaknya mencoba menjadi jawaban atas pertanyaan-pertanyaan spesifik.
Michael Durrant