Недавно я обсуждал с другим программистом лучший способ рефакторинга огромного (1000 строк) метода, полного операторов if.
Код написан на Java, но я думаю, что эта проблема может возникнуть и на других языках, таких как C #.
Чтобы решить эту проблему, он предложил использовать шаблон цепочки ответственности.
Он предложил иметь базовый класс «Хендлер». Затем «Handler1», «Handler2» и т. Д. Расширили бы «Handler».
Тогда у обработчиков будет метод «getSuccessor», который будет либо возвращать ноль (если он был последним в цепочке), либо следующий обработчик цепочки.
Затем функция handleRequest (Request) будет либо обрабатывать запрос, либо передавать его следующей цепочке, и, если ни одно из предыдущих решений не сработает, она будет возвращать только ноль или выбрасывать исключение.
Чтобы добавить новый обработчик в цепочку, кодировщик должен перейти к последнему элементу цепочки и сообщить ему, что появился новый элемент. Чтобы что-то сделать, он просто вызвал handleRequest для первого элемента цепочки.
Чтобы решить эту проблему, я предложил использовать другой подход.
У меня также будет базовый класс «Обработчик», с «Обработчиком1», «Обработчиком2», как и в предыдущем методе.
Однако не было бы метода "getSuccessor". Вместо этого у меня был бы класс Collection со списком обработчиков (Vector, ArrayList или что-то лучшее в этом случае).
Функция handleRequest все еще существует, но она не будет передавать вызов следующим обработчикам. Было бы просто обработать запрос или вернуть ноль.
Для обработки запроса можно использовать
for(Handler handle : handlers){
result = handle.handleRequest(request);
if(result!=null) return result;
}
throw new CouldNotParseRequestException(); //just like in the other approach
Или, чтобы предотвратить дублирование кода, в класс коллекции можно добавить метод parseRequest (request).
Чтобы добавить новый обработчик, нужно перейти к конструктору коллекции (или к статическому блоку {}, или к чему-нибудь эквивалентному) и просто добавить код «addHandler (new Handler3 ());».
Точно, какие преимущества цепочки ответственности мне не хватает при таком подходе? Какой метод является лучшим (при условии, что является лучшим методом)? Зачем? Какие потенциальные ошибки и проблемы может вызвать каждый метод проектирования?
Для тех, кому нужен контекст, вот как выглядел оригинальный код:
if(x instanceof Type1)
{
//doSomething1
} else if(x instanceof Type2)
{
//doSomething2
}
//etc.