Учитывая, что мы хотим уменьшить количество условных веток в нашем коде, мне интересно, можно ли занести в каталог все причины, по которым они существуют, чтобы затем мы могли в свою очередь перечислить несколько способов устранения каждой категории.
Для этого я перечислил происхождение условных обозначений, о которых я мог подумать. Это дурацкое поручение? Возможно, но все равно давайте попробуем. Пожалуйста, прокомментируйте, можете ли вы найти что-то, что я пропустил, и давайте посмотрим, сможем ли мы составить «полный» список…
- Проверка значения, возвращенного мне из кода, которым я владею.
В этом суть запаха Null Check, а в более общем смысле — Connascence of Value . Например, посмотрите этот (намеренно плохой) код из Книги Рефакторинга Уильяма К. Уэйка:public class Report { public static void report(Writer out, List<Machine> machines, Robot robot) throws IOException { //... out.write("Robot"); if (robot.location() != null) out.write(" location=" + robot.location().name()); if (robot.bin() != null) out.write(" bin=" + robot.bin()); //... } }
- Проверка значения, возвращенного мне из кода, которым я не владею.
Например, в проектах Rails мы часто видим код такого рода:if User.exists?(:user_id => current_user.id) # ... else # ... end
- Проверка параметра, переданного мне кодом, которым я владею.
Всякий раз, когда я пишу метод, который принимает логический параметр , я открываю себя для запаха управляющей пары. Вот пример из блога Петра Солнца :def say(sentence, loud = false) if loud puts sentence.upcase else puts sentence end end
- Проверка параметра, переданного мне кодом, который мне не принадлежит
Вот пример из документации по jQuery:<script> var xTriggered = 0; $( "#target" ).keypress(function( event ) { if ( event.which == 13 ) { event.preventDefault(); } xTriggered++; var msg = "Handler for .keypress() called " + xTriggered + " time(s)."; $.print( msg, "html" ); $.print( event ); }); </script>
- Проверка моего собственного состояния или атрибутов
Вот (намеренно плохой) пример из Рефакторинга Мартина Фаулера:class Employee { private int _type; static final int ENGINEER = 0; static final int SALESMAN = 1; static final int MANAGER = 2; Employee (int type) { _type = type; } int payAmount() { switch (_type) { case ENGINEER: return _monthlySalary; case SALESMAN: return _monthlySalary + _commission; case MANAGER: return _monthlySalary + _bonus; default: throw new RuntimeException("Incorrect Employee"); } } }
- Проверка значения, которое я установил ранее в этом методе.
Например:public String format(List<String> items) { StringBuffer s = new StringBuffer(); boolean first = true; for (String item : items) { if (first) first = false; else s.append(", "); s.append(item); } return s.toString(); }
- Проверка типа исключения, сгенерированного моим кодом.
Вот пример из документации по языку PHP:<?php function inverse($x) { if (!$x) { throw new Exception('Division by zero.'); } return 1/$x; } try { echo inverse(5) . "\n"; echo inverse(0) . "\n"; } catch (Exception $e) { echo 'Caught exception: ', $e->getMessage(), "\n"; } // Continue execution echo "Hello World\n"; ?>
- Проверка типа исключения, генерируемого кодом, которым я не владею.
Мы часто находим такой код в контроллерах Rails:def delete schedule_id = params[:scheduleId] begin Schedules.delete(schedule_id) rescue ActiveRecord::RecordNotFound render :json => "record not found" rescue ActiveRecord::ActiveRecordError # handle other ActiveRecord errors rescue # StandardError # handle most other errors rescue Exception # handle everything else end render :json => "ok" end
Этот список похож на полный? Может ли это быть?
Интересно, может ли быть полезным следующий шаг — записать некоторые общие стратегии удаления каждого из этих видов…?