Как избежать множества условий if-else?
Я прочитал много материалов о рефакторинге кода и о том, как избежать использования условных операторов if-else. У меня есть класс, в котором я использую много таких условий.
Вот подробнее: я использую парсер, и для каждой строки в моем SOAP-ответе я проверяю, есть ли интересующий меня тег. Если нет, то проверяю другой тег и так далее:
if(eventType == XmlPullParser.START_TAG) {
soapResponse= xpp.getName().toString();
if (soapResponse.equals("EditorialOffice")){
eventType = xpp.next();
if (xpp.getText() != null) {
editorialOffice += xpp.getText();
}
}
else if (soapResponse.equals("EditorialBoard")){
eventType = xpp.next();
if (xpp.getText() != null) {
editorialBoard += xpp.getText();
}
}
else if (soapResponse.equals("AdvisoryBoard")){
eventType = xpp.next();
if (xpp.getText() != null) {
advisoryBoard += xpp.getText();
}
}
}
eventType = xpp.next();
Теперь я хотел бы использовать что-то другое вместо этих условий if-else, но не знаю, что именно. Можете ли вы привести пример?
5 ответ(ов)
Попробуйте рассмотреть шаблон стратегии.
- Создайте интерфейс для обработки ответов (IMyResponse).
- Используйте этот IMyResponse для создания классов AdvisoryBoardResponse и EditorialBoardResponse.
- Создайте словарь, где ключом будет значение soapresponse, а значением - ваша стратегия.
- Затем вы сможете использовать методы класса IMyResponse, получая его из словаря.
Небольшой пример:
// Интерфейс
public interface IResponseHandler {
public void handleResponse(XmlPullParser xxp);
}
// Конкретный класс для обработки ответа редакционной коллегии
private class EditorialOfficeHandler implements IResponseHandler {
public void handleResponse(XmlPullParser xxp) {
// Реализуйте логику обработки ответа редакционной коллегии
}
}
// Конкретный класс для обработки ответа редакционного совета
private class EditorialBoardHandler implements IResponseHandler {
public void handleResponse(XmlPullParser xxp) {
// Реализуйте логику обработки ответа редакционного совета
}
}
В месте, где необходимо создать обработчики:
Map<String, IResponseHandler> strategyHandlers = new HashMap<String,IResponseHandler>();
strategyHandlers.put("EditorialOffice", new EditorialOfficeHandler());
strategyHandlers.put("EditorialBoard", new EditorialBoardHandler());
Когда вы получили ответ:
IResponseHandler responseHandler = strategyHandlers.get(soapResponse);
responseHandler.handleResponse(xxp);
Это позволит вам легко добавлять новые обработчики в будущем, просто создавая новые классы, реализующие интерфейс IResponseHandler и добавляя их в словарь.
В данном случае, поскольку код почти идентичен для всех трех случаев, кроме строки, к которой добавляется текст, я бы использовал карту (Map) для каждой из строк, которые мы собираем:
Map<String, String> map = new HashMap<String, String>();
map.put("EditorialOffice", "");
map.put("EditorialBoard", "");
map.put("AdvisoryBoard", "");
// можно использовать константы для строк выше или даже перечисление (enum)
А затем изменил бы ваш код на следующий:
if (eventType == XmlPullParser.START_TAG) {
soapResponse = xpp.getName().toString();
String current = map.get(soapResponse);
if (current != null && xpp.getText() != null) {
map.put(soapResponse, current += xpp.getText());
}
eventType = xpp.next();
}
Так вы избежите "if... then... else". Не нужно добавлять лишнюю сложность в виде множественных классов для паттернов стратегий и т.д. Карты (Maps) — ваш надежный помощник. Паттерн стратегии может быть полезен в некоторых ситуациях, но в этом случае задача достаточно проста, чтобы решить её без него.
В Java 7 можно использовать оператор SWITCH с объектами типа String. Это может быть полезным, если вы хотите сделать выбор между несколькими строковыми значениями. Например:
String fruit = "apple";
switch (fruit) {
case "apple":
System.out.println("You chose an apple.");
break;
case "banana":
System.out.println("You chose a banana.");
break;
case "orange":
System.out.println("You chose an orange.");
break;
default:
System.out.println("Unknown fruit.");
}
Такой подход делает код более читаемым и удобным для понимания, особенно если у вас много вариантов для сравнения. Просто помните, что SWITCH с строками начинает работать с Java 7, так что убедитесь, что ваш проект использует эту или более позднюю версию.
Кроме комментария zzzzzzz(и других), учтите, что вы используете XmlPullParser, что приводит к написанию довольно неаккуратного кода. Вы можете зарегистрировать несколько обратных вызовов, чтобы разбить ваш код на более читаемые части, но лучше всего использовать библиотеку SimpleXML или что-то подобное, если это возможно.
Также вы можете отрефакторить свой код, чтобы сделать его более читаемым и менее многословным. Например, зачем вы вызываете xpp.next()
внутри каждого условия? Почему бы не сделать это один раз вне условий:
if(eventType == XmlPullParser.START_TAG) {
soapResponse = xpp.getName().toString();
if (soapResponse.equals("EditorialOffice") && xpp.getText() != null) {
editorialOffice += xpp.getText();
}
else if (soapResponse.equals("EditorialBoard") && xpp.getText() != null) {
editorialBoard += xpp.getText();
}
else if (soapResponse.equals("AdvisoryBoard") && xpp.getText() != null) {
advisoryBoard += xpp.getText();
}
}
eventType = xpp.next();
Такой подход упростит ваш код и сделает его более понятным.
Вы можете создать интерфейс ResponseHandler
с тремя реализациями, по одной для каждого ветвления в вашем конструктиве if/else.
Затем можно использовать карту, которая связывает разные soapResponses
с обработчиком, или список, содержащий все обработчики, если они могут обрабатывать данный soapResponse
.
Также стоит переместить часть повторяющегося кода в общее абстрактное представление класса обработчика ответов.
Как часто бывает, существует множество вариаций. Используя дублирование кода, на самом деле вам нужна только одна реализация:
class ResponseHandler {
String stringToBuild = ""; // или что-то, что вам нужно
private final String matchString;
ResponseHandler(String aMatchString) {
matchString = aMatchString;
}
void handle(XppsType xpp) {
if (xpp.getName().toString().equals(matchString)) {
eventType = xpp.next();
if (xpp.getText() != null) {
stringToBuild += xpp.getText();
}
}
}
}
Ваш код становится:
List<ResponseHandler> handlers = Arrays.asList(
new ResponseHandler("EditorialOffice"),
new ResponseHandler("EditorialBoard"),
new ResponseHandler("AdvisoryBoard")
);
if(eventType == XmlPullParser.START_TAG) {
for(ResponseHandler h : handlers) {
h.handle(xpp);
}
}
Таким образом, ваш код становится более читаемым и структурированным, что упрощает добавление новых обработчиков в будущем.
Java: накладные расходы if vs. try/catch
Что значит 'synchronized'?
Почему нет ConcurrentHashSet, если есть ConcurrentHashMap?
Как объявить массив в одну строку?
Какие проблемы следует учитывать при переопределении equals и hashCode в Java?