Я пытаюсь написать сервлет, который выполняет задачу на основе значения "action", переданного в качестве входных данных.
Вот образец которого
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
*/
}
}
Все, что мне нужно, это избежать слишком большого количества проверок if / else-if в моем коде для лучшей читабельности и лучшего обслуживания кода. Так что пробовал для других альтернатив, таких как
1. переключить регистр - все еще он делает слишком много проверок перед выполнением моего действия
2. отражение
я] одна главная вещь - безопасность - которая позволяет мне получать доступ даже к переменным и методам в классе, несмотря на его спецификатор доступа - я не уверен, что я мог бы использовать это в своем коде
II], а с другой стороны, это занимает больше времени, чем простые проверки if / else-if
Есть ли лучший подход или лучший дизайн, который кто-то мог бы предложить организовать вышеприведенный код лучше?
отредактированный
Я добавил ответ для приведенного выше фрагмента, учитывая ответ ниже .
Но все же, следующие классы "ExecutorA" и "ExecutorB" делают только несколько строк кода. Полезно ли добавлять их как класс, а не как метод? Пожалуйста, посоветуйте в этом отношении.
источник
Ответы:
Основываясь на предыдущем ответе, Java позволяет перечислениям иметь свойства, чтобы вы могли определить шаблон стратегии, что-то вроде
Тогда ваша
Executor
(стратегия) будетИ все ваши if / else в вашем
doPost
методе становятся чем-то вродеТаким образом, вы можете даже использовать лямбды для исполнителей в перечислениях.
источник
Executor
является (или может быть) функциональным интерфейсом.Вместо использования отражения используйте выделенный интерфейс.
т.е. вместо:
использование
Реализует каждое из них для каждого действия, а затем:
Конечно, это решение не самое длинное, поэтому вам, возможно, не придется идти до такой длины.
источник
ProcessAction
аActionProcess
не так ли?Используйте шаблон команд , для этого потребуется интерфейс команд примерно такой:
Если
Actions
они легкие и дешевые в сборке, используйте фабричный метод. Загрузите имена классов из файла свойств, который отображаетactionName=className
и использует простой фабричный метод для создания действий для выполнения.Если Действия стоят дорого, используйте пул, такой как HashMap ; однако в большинстве случаев я бы предположил, что этого можно избежать в соответствии с принципом единой ответственности, делегируя дорогостоящий элемент некоторому заранее созданному общему пулу ресурсов, а не самим командам.
Затем они могут быть выполнены с
Это очень надежный и не связанный друг с другом подход, который применяет SRP, LSP и ISP принципов SOLID . Новые команды не изменяют код сопоставления команд. Команды просты в реализации. Их можно просто добавить в файл проекта и свойств. Команды должны быть входящими, и это делает их очень производительными.
источник
Вы можете использовать объект на основе перечисления, чтобы уменьшить потребность в жестком кодировании строковых значений. Это сэкономит вам время и сделает код более удобным для чтения и расширения в будущем.
источник
Шаблон Factory Method - это то, на что я обращаю внимание, если вы ищете масштабируемый и менее обслуживаемый дизайн.
Шаблон Factory Method определяет интерфейс для создания объекта, но пусть подкласс решает, какой класс создать. Фабричный метод позволяет отложить создание экземпляров класса до подкласса.
action1, action2 ........ actionN конкретная реализация с реализацией метода doStuff.
Просто позвони
Поэтому в будущем, если будет введено больше действий, вам просто нужно добавить конкретный класс.
источник
Со ссылкой на @J. Pichardo answer: Я пишу приведенный выше фрагмент кода следующим образом
источник