Katakanlah saya memiliki Door
s yang dikelola oleh DoorService
. The DoorService
bertanggung jawab atas pembukaan, menutup dan mengunci pintu yang disimpan di database.
public interface DoorService
{
void open(Door door) throws DoorLockedException, DoorAlreadyOpenedException;
void close(Door door) throws DoorAlreadyClosedException;
/**
* Closes the door if open
*/
void lock(Door door) throws DoorAlreadyLockedException;
}
Untuk metode kunci, ada a DoorAlreadyLockedException
dan untuk metode terbuka ada a DoorLockedException
. Ini adalah opsi tetapi ada opsi lain yang memungkinkan:
1) Gunakan DoorLockedException
untuk semuanya, agak canggung ketika menangkap pengecualian pada lock()
panggilan
try
{
doorService.lock(myDoor);
}
catch(DoorLockedException ex) // door ALREADY locked
{
//error handling...
}
2) Memiliki 2 jenis pengecualian DoorLockedException
danDoorAlreadyLockedException
3) Memiliki 2 tipe pengecualian tetapi biarkan DoorAlreadyLockedException extends DoorLockedException
Solusi mana yang terbaik dan mengapa?
java
exceptions
class-design
Musim dingin
sumber
sumber
Jawaban:
Saya tahu orang-orang membuat masalah besar menggunakan pengecualian untuk kontrol aliran tapi itu bukan masalah terbesar di sini. Saya melihat pelanggaran pemisahan permintaan perintah besar . Tetapi itu pun bukan yang terburuk.
Tidak, yang terburuk ada di sini:
Kenapa segalanya meledak jika asumsi Anda tentang keadaan pintu salah tetapi
lock()
hanya memperbaikinya untuk Anda? Lupa bahwa ini membuat tidak mungkin untuk mengunci pintu terbuka, yang sangat mungkin dan sesekali berguna. Tidak masalah di sini adalah Anda telah mencampur dua filosofi yang berbeda untuk berurusan dengan asumsi yang salah. Itu membingungkan. Jangan lakukan itu. Tidak pada tingkat abstraksi yang sama dengan gaya penamaan yang sama. Ow! Bawa salah satu ide itu ke luar. Metode layanan pintu semua harus bekerja dengan cara yang sama.Adapun pelanggaran Pemisahan Permintaan Perintah saya tidak harus mencoba untuk menutup pintu untuk mencari tahu apakah itu ditutup atau terbuka. Aku seharusnya bisa bertanya. Layanan pintu tidak menyediakan cara untuk melakukan itu tanpa mungkin mengubah keadaan pintu. Itu membuat ini jauh lebih buruk daripada perintah yang juga terjadi untuk mengembalikan nilai (kesalahpahaman umum tentang apa CQS tentang). Di sini, perintah perubahan negara adalah satu-satunya cara untuk melakukan kueri! Ow!
Adapun pengecualian lebih mahal daripada kode status, itu pembicaraan optimasi. Cukup cepat cukup cepat. Tidak masalah sebenarnya adalah bahwa manusia tidak mengharapkan pengecualian untuk kasus tipikal. Anda dapat berdebat tentang apa yang paling Anda sukai. Bagi saya pertanyaan besarnya adalah seberapa mudah Anda membuat kode menggunakan.
Tolong jangan buat saya menulis kode seperti ini. Tolong beri kami
isLocked()
danisClosed()
metode. Dengan itu saya bisa menulis sendiriensureClosed()
danensureUnlocked()
metode yang mudah dibaca. Yang hanya membuang jika kondisi pos mereka dilanggar. Saya lebih suka menemukan Anda sudah menulis dan mengujinya tentu saja. Hanya saja, jangan mencampurnya dengan yang melempar ketika mereka tidak dapat mengubah negara. Paling tidak beri mereka nama yang berbeda.Apa pun yang Anda lakukan, tolong jangan panggil apa pun
tryClose()
. Itu nama yang mengerikan.Adapun
DoorLockedException
sendirian vs jugaDoorAlreadyLockedException
sakit mengatakan ini: ini semua tentang menggunakan kode. Tolong jangan merancang layanan seperti ini tanpa menulis kode menggunakan dan melihat kekacauan yang Anda buat. Refactor dan mendesain ulang sampai menggunakan kode setidaknya dapat dibaca. Bahkan, pertimbangkan untuk menulis menggunakan kode terlebih dahulu.sumber
lock()
metode yang memanggilclose()
itu hanya aku yang malas saat menulis pertanyaan, tapi terima kasih untuk membuat saya sadar bahwa! Saya tidak akan jatuh cinta ketika menulis kode nyata. Dalam kasus saya, 3 metode tidak pernah benar-benar dipanggil secara berturut-turut. Hanya saja: panggil satu, jika tidak ada pengecualian yang baik, jika tidak, tampilkan dialog yang diterjemahkan dan mungkin keluar (jika InvalidTokenException). Saya punyaisLocked()
danisOpen()
metode dan mereka digunakan dalam aliran kontrol server tetapi mereka tidak boleh digunakan sebagai cara untuk memeriksa apakah dialog kesalahan harus ditampilkan, itu pekerjaan untuk pengecualian.DoorAlreadyLockedException
tetapi membuat kelas kembar.public class DoorAlreadyLockedException inherits DoorLockedException {}
. Tentukan kelas dalam satu baris hanya demi memberinya nama yang bagus. Pilih dari mana Anda mewarisi dengan bijak. Saya lebih suka mewarisi dari tempat setinggi yang saya bisa, meski tidak berlebihan, untuk menghindari rantai pewarisan yang lama.NoOneGaveMeAKey
menjadiNoOneGaveMeAKeyException
hanya untuk menjadi mewah. Kalau tidak, saya setuju dengan poin utama yaitu sebelum diproses, kita harus bisa mengetahui keadaan objek.isOpen
/isClosed
tidak cukup baik. Pikirkan tentang sistem file. Anda dapat memeriksa file yang ada / tidak ada, tetapi itu masih bisa berubah pada saat Anda mencoba membaca atau menulisnya, danIOException
hasilnya akan. Mungkin dalam konteks ini benar-benar ada peluang negara tidak valid ketika Anda membuka atau menutup pintu.Membuat perbedaan antara
DoorLockedException
danDoorAlreadyLockedException
menyarankan bahwa berbagai jenis pengecualian sedang digunakan untuk kontrol aliran, praktik yang sudah secara luas dianggap sebagai antipattern.Memiliki beberapa tipe pengecualian untuk sesuatu yang tidak berbahaya ini gratis. Kompleksitas tambahan tidak sebanding dengan manfaat tambahan.
Cukup gunakan
DoorLockedException
untuk semuanya.Lebih baik lagi, lakukan saja. Jika pintu sudah terkunci, maka masih akan dalam kondisi yang benar ketika
lock()
metode selesai. Jangan melempar pengecualian untuk kondisi yang biasa-biasa saja.Jika Anda masih merasa tidak nyaman dengan itu, ubah nama metode Anda
ensureDoorLocked()
.sumber
DoorLockedException
danDoorAlreadyLockedException
menyarankan bahwa, itu hanya tentang memiliki penangan kesalahan yang jauh lebih signifikan untuklock()
metode ini dengan biaya memiliki kelas yang hampir digandakan.Subjek dari pertanyaan ini "Haruskah jenis pengecualian daur ulang lebih disukai daripada yang digunakan sekali pakai?" tampaknya telah diabaikan, tidak hanya dalam jawaban, tetapi dalam perincian untuk pertanyaan (jawabannya adalah untuk perincian pertanyaan).
Saya setuju dengan sebagian besar kritik terhadap kode yang ditawarkan responden.
Tetapi sebagai jawaban untuk pertanyaan utama, saya akan mengatakan bahwa Anda harus lebih suka menggunakan kembali 'pengecualian daur ulang' daripada 'penggunaan tunggal'.
Dalam penggunaan penanganan pengecualian yang lebih umum, Anda memiliki JARAK yang luar biasa dalam kode antara tempat pengecualian terdeteksi dan dibuang, dan di mana pengecualian ditangkap dan ditangani. Itu berarti menggunakan tipe pribadi (modular) dalam penanganan pengecualian pada umumnya tidak akan berfungsi dengan baik. Program tipikal dengan penanganan pengecualian - akan memiliki beberapa lokasi tingkat atas dalam kode di mana pengecualian ditangani. Dan karena itu adalah lokasi tingkat atas, sulit bagi mereka untuk memiliki pengetahuan terperinci tentang aspek-aspek sempit dari modul tertentu.
Sebaliknya, mereka kemungkinan akan memiliki penangan tingkat tinggi untuk beberapa masalah tingkat tinggi.
Satu-satunya alasan menggunakan kelas pengecualian kustom terperinci tampaknya masuk akal dalam sampel Anda, adalah karena (dan di sini saya membayangi responden lain) - Anda tidak boleh menggunakan penanganan pengecualian untuk aliran kontrol biasa.
sumber
Alternatif yang belum dijelajahi. Anda mungkin memodelkan hal yang salah dengan kelas Anda, bagaimana jika Anda memiliki ini?
Sekarang tidak mungkin untuk mencoba sesuatu yang merupakan kesalahan. Anda tidak memerlukan pengecualian.
sumber
Saya akan menjawab pertanyaan asli, daripada mengkritik contohnya.
Sederhananya, jika Anda berharap bahwa klien mungkin perlu bereaksi berbeda untuk setiap kasus, itu menjamin jenis pengecualian baru.
Jika Anda memutuskan untuk menggunakan beberapa jenis pengecualian dan Anda masih berharap bahwa klien dalam beberapa kasus ingin membuat klausa tangkapan umum untuk mereka, Anda mungkin harus membuat superclass abstrak yang mereka berdua kembangkan.
sumber
Ini pseudocode tapi saya pikir Anda akan mendapatkan apa yang saya maksud:
Ya, penggunaan kembali jenis pengecualian masuk akal, jika Anda menggunakan pengecualian untuk hal-hal yang benar-benar luar biasa . Karena hal-hal yang benar-benar luar biasa sebagian besar masalah lintas sektoral. Anda menggunakan Pengecualian pada dasarnya untuk aliran kontrol dan itu mengarah ke masalah tersebut.
sumber
DoorStuckException
danHouseOnFireException
tidak harus diperiksa, itu tidak dimaksudkan untuk ditangkap pada semua panggilan.