Saya mencoba untuk menulis servlet yang melakukan tugas berdasarkan nilai "action" yang diteruskan sebagai input.
Berikut adalah contohnya
public class SampleClass extends HttpServlet {
public static void action1() throws Exception{
//Do some actions
}
public static void action2() throws Exception{
//Do some actions
}
//And goes on till action9
public void doPost(HttpServletRequest req, HttpServletResponse res)throws ServletException, IOException {
String action = req.getParameter("action");
/**
* I find it difficult in the following ways
* 1. Too lengthy - was not comfortable to read
* 2. Makes me fear that action1 would run quicker as it was in the top
* and action9 would run with a bit delay - as it would cross check with all the above if & else if conditions
*/
if("action1".equals(action)) {
//do some 10 lines of action
} else if("action2".equals(action)) {
//do some action
} else if("action3".equals(action)) {
//do some action
} else if("action4".equals(action)) {
//do some action
} else if("action5".equals(action)) {
//do some action
} else if("action6".equals(action)) {
//do some action
} else if("action7".equals(action)) {
//do some action
} else if("action8".equals(action)) {
//do some action
} else if("action9".equals(action)) {
//do some action
}
/**
* So, the next approach i tried it with switch
* 1. Added each action as method and called those methods from the swith case statements
*/
switch(action) {
case "action1": action1();
break;
case "action2": action2();
break;
case "action3": action3();
break;
case "action4": action4();
break;
case "action5": action5();
break;
case "action6": action6();
break;
case "action7": action7();
break;
case "action8": action8();
break;
case "action9": action9();
break;
default:
break;
}
/**
* Still was not comfortable since i am doing un-necessary checks in one way or the other
* So tried with [reflection][1] by invoking the action methods
*/
Map<String, Method> methodMap = new HashMap<String, Method>();
methodMap.put("action1", SampleClass.class.getMethod("action1"));
methodMap.put("action2", SampleClass.class.getMethod("action2"));
methodMap.get(action).invoke(null);
/**
* But i am afraid of the following things while using reflection
* 1. One is Security (Could any variable or methods despite its access specifier) - is reflection advised to use here?
* 2. Reflection takes too much time than simple if else
*/
}
}
Yang saya butuhkan adalah keluar dari terlalu banyak if / else-if memeriksa kode saya untuk keterbacaan yang lebih baik dan pemeliharaan kode yang lebih baik. Maka dicoba untuk alternatif lain seperti
1. sakelar kasus - masih tetap melakukan terlalu banyak pemeriksaan sebelum melakukan tindakan
2. refleksi
i] satu hal utama adalah keamanan - yang memungkinkan saya untuk mengakses bahkan variabel dan metode di dalam kelas meskipun ada specifier aksesnya - saya tidak yakin cuaca saya bisa menggunakannya dalam kode saya
ii] dan yang lainnya membutuhkan waktu lebih dari sekadar pemeriksaan if / else-if
Apakah ada pendekatan yang lebih baik atau desain yang lebih baik yang seseorang sarankan untuk mengatur kode di atas dengan cara yang lebih baik?
Diedit
Saya telah menambahkan jawaban untuk cuplikan di atas dengan mempertimbangkan jawaban di bawah ini .
Tapi tetap saja, kelas-kelas berikut "ExecutorA" dan "ExecutorB" hanya melakukan beberapa baris kode. Apakah ini praktik yang baik untuk menambahkan mereka sebagai kelas daripada menambahkannya sebagai metode? Mohon saran dalam hal ini.
sumber
Jawaban:
Berdasarkan jawaban sebelumnya, Java memungkinkan enum memiliki properti sehingga Anda bisa menentukan pola strategi, seperti
Maka
Executor
(Strategi) Anda akan menjadiDan semua if / else Anda dalam
doPost
metode Anda menjadi sesuatu sepertiDengan cara ini Anda bahkan bisa menggunakan lambdas untuk pelaksana di enum.
sumber
Executor
adalah (atau bisa) antarmuka fungsional.Alih-alih menggunakan refleksi, gunakan antarmuka khusus.
yaitu bukannya:
Menggunakan
Menerapkan masing-masing untuk setiap tindakan dan kemudian:
Tentu saja solusi ini bukan yang tertinggi, jadi Anda mungkin tidak perlu sampai sejauh itu.
sumber
ProcessAction
bukannyaActionProcess
begitu ...?Gunakan Pola Perintah , ini akan membutuhkan Command Interface sesuatu seperti ini:
Jika
Actions
yang ringan dan murah untuk membangun kemudian gunakan Metode Pabrik. Memuat nama kelas dari file properti yang memetakanactionName=className
dan menggunakan metode pabrik sederhana untuk membangun tindakan untuk eksekusi.Jika Actions mahal untuk dibangun maka gunakan pool, seperti HashMap ; namun dalam kebanyakan kasus saya menyarankan ini bisa dihindari berdasarkan Prinsip Tanggung Jawab Tunggal mendelegasikan elemen mahal ke beberapa kumpulan sumber daya bersama yang sudah dibangun sebelumnya daripada perintah itu sendiri.
Ini kemudian dapat dieksekusi dengan
Ini adalah pendekatan yang sangat kuat dan terpisah yang menerapkan SRP, LSP dan ISP dari prinsip-prinsip SOLID . Perintah baru tidak mengubah kode perintah mapper. Perintahnya sederhana untuk diimplementasikan. Mereka dapat ditambahkan ke file proyek dan properti. Perintah harus masuk kembali dan ini membuatnya sangat performant.
sumber
Anda dapat menggunakan objek berbasis enumerasi untuk mengurangi kebutuhan hardCoding nilai string. Ini akan menghemat waktu Anda dan membuat kode lebih rapi untuk dibaca & diperluas di masa depan.
sumber
Pola Metode Pabrik adalah apa yang saya lihat jika Anda mencari desain yang skalabel dan kurang dapat dirawat.
Pola Metode Pabrik mendefinisikan antarmuka untuk membuat objek, tetapi biarkan subclass memutuskan kelas mana yang akan dipakai. Metode Pabrik memungkinkan instantiation penangguhan kelas untuk subkelas.
action1, action2 ........ actionN implementasi konkret dengan mengimplementasikan doStuff Method untuk melakukan sesuatu.
Panggil saja
Jadi di masa depan jika lebih banyak tindakan diperkenalkan, Anda hanya perlu menambahkan kelas konkret.
sumber
Dengan mengacu pada @J. Pichardo menjawab saya menulis cuplikan di atas sebagai berikut
sumber