Bagaimana memberi nama metode yang melakukan tugas sekaligus mengembalikan boolean sebagai status?

33

Jika ada metode

bool DoStuff() {
    try {
        // doing stuff...
        return true;
    }
    catch (SomeSpecificException ex) {
        return false;
    }
}

haruskah lebih baik disebut IsStuffDone()?

Kedua nama bisa disalahtafsirkan oleh pengguna: Jika nama itu DoStuff()mengapa ia mengembalikan boolean? Jika namanya IsStuffDone()tidak jelas apakah metode melakukan tugas atau hanya memeriksa hasilnya.

Apakah ada konvensi untuk kasus ini? Atau pendekatan alternatif, karena yang ini dianggap cacat? Misalnya dalam bahasa yang memiliki parameter output, seperti C #, variabel status boolean dapat diteruskan ke metode sebagai satu dan tipe pengembalian metode akan void.

EDIT: Dalam penanganan pengecualian masalah khusus saya tidak dapat didelegasikan secara langsung ke pemanggil, karena metode ini merupakan bagian dari implementasi antarmuka. Oleh karena itu, penelepon tidak dapat dituntut berurusan dengan semua pengecualian implementasi yang berbeda. Itu tidak akrab dengan pengecualian itu. Namun, penelepon dapat menangani pengecualian khusus seperti StuffHasNotBeenDoneForSomeReasonExceptionyang disarankan dalam jawaban dan komentar npinti .

Pengasingan Limbo
sumber
2
Itu tergantung pada penggunaan fungsi dan hal-hal yang sedang dilakukan. Jika perlu, bahwa hal-hal tersebut perlu dijalankan dengan benar, maka saya akan menganggap pendekatan ini cacat, karena pengguna fungsi mungkin kehilangan bendera boolean dan juga tidak memiliki informasi yang diberikan oleh pengecualian.
Benni
7
Sebagian besar waktu, saya akan menyebutnya "rusak" sebagai mengembalikan booleanbukannya membungkus atau melewati pengecualian hampir selalu salah.
maaartinus
2
Handler pengecualian semacam ini jarang merupakan ide yang bagus. Hanya menangkap pengecualian spesifik yang Anda harapkan, tidak semuanya. Dan jika mungkin hindari melemparkannya di tempat pertama, menghilangkan kebutuhan untuk menangkapnya.
CodesInChaos
2
Umm ... BadlyDesignedMethodInSeriousNeedOfRefactoring? Dan untuk menjawab pertanyaan Anda tentang pengecualian - Saya akan membiarkan penelepon menangani mereka, atau menangkap mereka dan kemudian melemparkan pengecualian khusus yang berarti "metode ini tidak melakukan tugasnya". Bagikan dan nikmati.
Bob Jarvis - Reinstate Monica
5
Untuk semua orang yang mengatakan: cukup lempar (atau biarkan) pengecualian, Anda membuat asumsi yang tidak berdasar tentang bagaimana kode ini digunakan. Satu skenario yang mungkin adalah bahwa ada masalah yang harus dipecahkan, dengan berbagai metode solusi heuristik yang memecahkan subkelas masalah yang semakin besar dengan biaya yang semakin meningkat; masuk akal untuk menulis sesuatu seperti if (FirstMethodSucceeds(problem) or SecondMethodSucceeds(problem) or ...) Hurray(); else UniversalSolve(problem);. Melakukan hal yang sama dengan pengecualian (kebiasaan?) Akan sia-sia lebih rumit.
Marc van Leeuwen

Jawaban:

68

Di .NET, Anda sering memiliki pasangan metode di mana salah satu dari mereka mungkin melempar pengecualian ( DoStuff), dan yang lainnya mengembalikan status Boolean dan, pada eksekusi yang sukses, hasil aktual melalui parameter keluar ( TryDoStuff).

(Microsoft menyebut ini "Try-Parse Pattern" , karena mungkin contoh yang paling menonjol untuk itu adalah TryParsemetode dari berbagai jenis primitif.)

Jika Tryawalan tidak biasa dalam bahasa Anda, maka Anda mungkin tidak boleh menggunakannya.

ne2dmar
sumber
3
+1 Ini adalah bagaimana saya melihat hal semacam ini dilakukan di tempat lain. if (TryDoStuff()) print("Did stuff"); else print("Could not do stuff");adalah idiom yang cukup standar dan intuitif menurut saya.
Karl Nicoll
12
Perlu dicatat bahwa TryDoStuffmetode diasumsikan gagal dengan bersih dan tidak memiliki efek samping ketika mereka kembali salah.
Trillian
FYI, ada juga Removemetode misalnya dalam kerangka NET. Yang akan menghapus elemen dari struktur data (misalnya Dictionary), dan mengembalikan a bool. Konsumen API dapat memutuskan untuk mengonsumsinya atau mengabaikannya. Namun, kesalahan dilaporkan sebagai pengecualian.
Omer Iqbal
18

Bagaimana jika Anda hanya melemparkan pengecualian ke kode panggilan?

Dengan cara ini Anda mendelegasikan penanganan pengecualian kepada siapa yang pernah menggunakan kode Anda. Bagaimana jika, di masa depan Anda ingin melakukan hal berikut:

  • Jika tidak ada pengecualian yang dilemparkan, lakukan tindakan A
  • Jika (misalnya) a FileNotFoundExceptiondilemparkan, ambil tindakan B
  • Jika ada pengecualian lain yang dilemparkan, ambil tindakan C

Jika Anda membuang kembali pengecualian Anda, perubahan di atas hanya akan memerlukan penambahan catchblok tambahan . Jika Anda membiarkannya apa adanya, Anda perlu mengubah metode dan tempat dari mana metode ini dipanggil, yang, tergantung pada kompleksitas proyek, dapat berada di beberapa lokasi.

npinti
sumber
1
Bagaimana jika pengecualiannya tidak dapat didelegasikan dan harus ditangani secara internal?
Limbo Exile
2
@LimboExile: Saya pikir Anda masih bisa mengatasinya secara internal dan kemudian, mungkin melemparkan pengecualian lain, mungkin Anda sendiri. Ini akan menggambarkan bahwa sesuatu yang seharusnya tidak terjadi terjadi, tetapi pada saat yang sama, Anda tidak mengungkapkan apa yang sebenarnya terjadi di bawah tenda, yang saya asumsikan adalah mengapa Anda ingin menangani pengecualian secara internal.
npinti
6
Mungkin perlu diingat bahwa melemparkan pengecualian harus untuk kasus luar biasa . Jika itu umum atau normal untuk DoStuffgagal, melemparkan pengecualian untuk kasus kegagalan akan sama dengan mengendalikan aliran program dengan pengecualian yang buruk. Pengecualian juga memiliki biaya kinerja yang melekat. Jika DoStuffgagal adalah kasus yang tidak biasa karena kesalahan, maka pengecualian pasti adalah cara untuk pergi seperti yang disarankan @npinti.
Karl Nicoll
1
@KarlNicoll Apakah ada sesuatu yang "luar biasa" sepenuhnya subjektif. Kriteria utama haruslah apakah Anda ingin program macet jika tidak ada yang melakukan sesuatu tentang kesalahan tersebut, dan apakah Anda ingin kemungkinan kesalahan hadir dalam tipe fungsi. Selain itu, bukan fakta bahwa pengecualian itu mahal; itu tergantung pada bahasa dan bagaimana Anda melemparkannya. Pengecualian adalah murah di Python, dan jika Anda menghapus informasi jejak stack mereka bisa murah di Jawa juga. Bahkan jika ada biaya kinerja, itu adalah pengoptimalan prematur yang perlu dikhawatirkan sampai Anda membuat profil.
Doval
1
@Doval - Saya setuju bahwa ini subjektif, karena itulah OP tidak boleh mengabaikan jawaban npinti sepenuhnya, karena itu bisa menjadi tindakan terbaik. Maksud saya adalah melemparkan pengecualian tidak selalu merupakan jalan terbaik untuk diambil. Ada banyak kasus di mana kegagalan tidak membenarkan melempar pengecualian dan berpotensi crash aplikasi. Misalnya, jika DoStuff()metode OP membersihkan setelah kode bagian dalam mengeluarkan pengecualian, dan Post-conditions dari metode tersebut masih benar, kode kembali mungkin merupakan opsi yang lebih baik karena kesalahan telah ditangani.
Karl Nicoll
7

DoStuff() sudah cukup, dan nilai pengembalian fungsi harus didokumentasikan, dan Anda tidak perlu menyebutkannya dalam nama fungsi, mencari banyak API yang tersedia:

PHP

// this method update and return the number affected rows 
// called update instead of updateAndGetAffectedCount
$affected = $query->update(/* values */);

C-Sharp

// Remove item from the List
// returns true if item is successfully removed; otherwise, false.
public bool Remove( T item )
amd
sumber
6

Di Jawa, API Pengumpulan menetapkan metode tambahkan yang mengembalikan boolean. Ini pada dasarnya mengembalikan apakah add mengubah koleksi. Jadi untuk a Listbiasanya akan mengembalikan true, karena item ditambahkan, sedangkan untuk a Setitu mungkin kembali palsu, jika item sudah ada di sana, karena Sets memungkinkan setiap item unik paling banyak sekali.

Yang mengatakan, jika Anda menambahkan item yang tidak diizinkan oleh koleksi, misalnya, nilai nol, tambahnya akan melempar NullPointerExceptionbukan mengembalikan false.

Ketika Anda menerapkan logika yang sama untuk kasus Anda, mengapa Anda harus mengembalikan boolean? Jika ingin menyembunyikan pengecualian, jangan. Hanya melempar pengecualian. Dengan begitu Anda bisa melihat apa yang salah. Jika Anda memang membutuhkan boolean, karena mungkin tidak dilakukan, karena alasan lain selain pengecualian, beri nama metode DoStuff(), karena itu mewakili perilaku. Itu hal.

mrjink
sumber
1

Mungkin gagal karena berbagai alasan, Pengecualian, kondisi normal, jadi gunakan ini:

boolean doStuff() - returns true when successful

Penting untuk mendokumentasikan apa yang dimaksud boolean.

pengguna136354
sumber
1

Saya biasanya memiliki metode mengembalikan OperationResult(atau OperationResult<T>) dan mengatur IsSuccessproperti pada yang OperationResulttepat. Jika metode 'biasa' batal lalu kembali OperationResult, jika metode 'biasa' mengembalikan objek kemudian kembali OperationResult<T>dan atur Itemproperti pada yang OperationResultsesuai. Saya juga menyarankan memiliki metode OperationResultseperti .Failed(string reason)dan .Succeeded(T item). OperationResultdengan cepat menjadi tipe yang biasa di sistem Anda dan pengembang bisa tahu bagaimana menanganinya.

Scott Rickman
sumber
0

Ini benar-benar tergantung pada bahasa yang Anda gunakan. Seperti untuk beberapa bahasa ada konvensi dan protokol yang benar-benar tidak ada dalam banyak bahasa atau sama sekali.

Misalnya, dalam bahasa Objective-C dan nama metode iOS / Mac OS X SDK biasanya mengikuti baris dari:

- (returndatatype) viewDidLoad {
- (returndatatype) isVisible {
- (returndatatype) appendMessage:datatype variablename with:datatype variablename {

Seperti yang Anda lihat, ada metode yang disebut viewDidLoad. Saya lebih suka menggunakan penamaan jenis ini setiap kali saya membuat aplikasi sendiri. Ini dapat digunakan untuk memeriksa apakah sesuatu seharusnya terjadi seperti yang Anda katakan. Saya percaya bahwa Anda berpikir terlalu dalam tentang apa yang Anda beri nama metode Anda. Sebagian besar metode mengembalikan status apa yang mereka lakukan terlepas dari itu, ambil contoh:

Di PHP, mysql_connect () akan mengembalikan false jika koneksi gagal. Itu tidak mengatakan itu akan, tetapi itu terjadi dan dokumentasi mengatakan itu sehingga tidak dapat disalahartikan kepada programmer.

Gergy008
sumber
Ah, tetapi viewDidLoad lebih merupakan notifikasi panggilan balik. Pengguna tidak menyebutnya untuk memuat tampilan. Sebaliknya, ini disebut setelah tampilan dimuat. Demikian juga: isVisible tidak mengatur visibilitas, melainkan hanya mengembalikan nilai saat ini. Itu tidak melakukan apa - apa.
lilbyrdie
0

Saya ingin menyarankan untuk menggunakan awalan 'Coba'. Ini adalah pola yang sudah diketahui untuk situasi-situasi di mana metode ini mungkin berhasil atau tidak. Pola penamaan ini telah digunakan oleh Microsoft dalam .NET Framework (misalnya, TryParseInt).

Tapi, mungkin ini bukan soal penamaan. Ini tentang bagaimana Anda merancang parameter input / output metode Anda.

Ide saya adalah jika suatu metode memiliki nilai balik, maka tujuan memanggil metode itu adalah untuk mendapatkan nilai balik itu. Jadi, Anda harus menghindari menggunakan tipe pengembalian untuk menunjukkan status operasi.

Dalam C #, saya lebih suka menggunakan parameter keluar. Menggunakan keluar saya menandai parameter sebagai parameter samping. Khususnya bahwa C # 6 akan mendukung deklarasi variabel inline.

DoStuff(out var isStuffDone); // The out parameter name clearly states its purpose.
DoStuff(out var _); // I use _ for naming parameters that I am ignoring.
000
sumber
0

Saya akan memilih nama berdasarkan peran utama metode ini. Kenyataannya, metode itu mengembalikan nilai boolean tanpa mandat awalan 'Is'. Mari kita memiliki beberapa kode Java, yang menggunakan awalan 'Is' dengan cukup luas. Lihatlah java.io.File.delete(). Itu kembali boolean, tetapi tidak disebut isFileDeleted(). Alasannya adalah bahwa peran utama dari metod adalah untuk menghapus file. Seseorang memanggil metode ini dengan maksud untuk menghapus file.

Boolean ada di sana hanya untuk mengkomunikasikan kembali hasil pekerjaan. Di sisi lain, mari kita lihat java.util.Map.isEmpty(). Jelas, Anda memanggil metode seperti itu untuk mengetahui apakah koleksi itu kosong. Anda tidak ingin semua hal dilakukan. Anda hanya ingin mengetahui keadaan saat ini.

Jadi secara pribadi, saya akan tetap menggunakan DoStuff().

Ini agak masalah yang sangat penting bagi saya. Sering kali ketika saya mempertahankan kode warisan, saya menemukan sesuatu yang saya sebut secara pribadi "metode berbohong". Namanya menunjukkan tindakan A, tetapi tubuh melakukan tindakan B. Contoh paling aneh menggunakan metode pengambil data yang berubah dalam database.

Jacek Prucia
sumber