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