Чистый код. Создание, анализ и рефакторинг (Мартин) - страница 36

• Чтобы включить пакетные начальные блоки, мы ищем в родительской иерархии страницу SuiteSetUp и добавляем команду include с путем к этой странице.

• Чтобы найти в родительской иерархии…

Опыт показывает, что программистов очень трудно научить следовать этому правилу и писать функции, остающиеся на одном уровне абстракции. Тем не менее освоить этот прием очень важно. Он играет ключевую роль для создания коротких функций, выполняющих только одну операцию. Построение кода по аналогии с набором последовательных TO-абзацев — эффективный метод поддержания единого уровня абстракции.

Взгляните на листинг 3.7 в конце этой главы. В нем приведен полный код функции testableHtml, переработанной в соответствии с описанными здесь принципами. Обратите внимание на то, как каждая функция «представляет» читателю следующую функцию и как каждая функция остается на едином уровне абстракции.

Команды switch

Написать компактную команду switch довольно сложно[14]. Даже команда switch всего с двумя условиями занимает больше места, чем в моем представлении должен занимать один блок или функция. Также трудно создать команду switch, которая делает что-то одно — по своей природе команды switch всегда выполняют N операций. К сожалению, обойтись без команд switch удается не всегда, но по крайней мере мы можем позаботиться о том, чтобы эти команды были скрыты в низкоуровневом классе и не дублировались в коде. И конечно, в этом нам может помочь полиморфизм.

В листинге 3.4 представлена всего одна операция, зависящая от типа работника.


Листинг 3.4. Payroll.java

>public Money calculatePay(Employee e)

>throws InvalidEmployeeType {

>    switch (e.type) {

>      case COMMISSIONED:

>        return calculateCommissionedPay(e);

>      case HOURLY:

>        return calculateHourlyPay(e);

>      case SALARIED:

>        return calculateSalariedPay(e);

>      default:

>        throw new InvalidEmployeeType(e.type);

>    }

>  }

Эта функция имеет ряд недостатков. Во-первых, она велика, а при добавлении новых типов работников она будет разрастаться. Во-вторых, она совершенно очевидно выполняет более одной операции. В-третьих, она нарушает принцип единой ответственности[15], так как у нее существует несколько возможных причин изменения. В-четвертых, она нарушает принцип открытости/закрытости[16], потому что код функции должен изменяться при каждом добавлении новых типов. Но, пожалуй, самый серьезный недостаток заключается в том, что программа может содержать неограниченное количество других функций с аналогичной структурой, например:

>isPayday(Employee e, Date date)