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

или

>deliverPay(Employee e, Money pay)

и так далее. Все эти функции будут иметь все ту же ущербную структуру.

Решение проблемы (листинг 3.5) заключается в том, чтобы похоронить команду switch в фундаменте АБСТРАКТНОЙ ФАБРИКИ [GOF] и никому ее не показывать. Фабрика использует команду switch для создания соответствующих экземпляров потомков Employee, а вызовы функций calculatePay, isPayDay, deliverPay и т.д. проходят полиморфную передачу через интерфейс Employee.


Листинг 3.5. Employee и Factory

>public abstract class Employee {

>  public abstract boolean isPayday();

>  public abstract Money calculatePay();

>  public abstract void deliverPay(Money pay);

>}

>-----------------

>public interface EmployeeFactory {

>  public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType;

>}

>-----------------

>public class EmployeeFactoryImpl implements EmployeeFactory {

>  public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType {

>    switch (r.type) {

>      case COMMISSIONED:

>        return new CommissionedEmployee(r) ;

>      case HOURLY:

>        return new HourlyEmployee(r);

>      case SALARIED:

>        return new SalariedEmploye(r);

>      default:

>        throw new InvalidEmployeeType(r.type);

>    }

>  }

>}

Мое общее правило в отношении команд switch гласит, что эти команды допустимы, если они встречаются в программе однократно, используются для создания полиморфных объектов и скрываются за отношениями наследования, чтобы оставаться невидимыми для остальных частей системы [G23]. Конечно, правил без исключений не бывает и в некоторых ситуациях приходится нарушать одно или несколько условий этого правила.

Используйте содержательные имена

В листинге 3.7 я переименовал нашу функцию testableHtml в SetupTeardownIncluder.render. Новое имя гораздо лучше, потому что оно точнее описывает, что делает функция. Кроме того, всем приватным методам были присвоены столь же содержательные имена isTestable, includeSetupAndTeardownPages и т.д. Трудно переоценить пользу хороших имен. Вспомните принцип Уорда: «Вы работаете с чистым кодом, если каждая функция в основном делает то, что вы от нее ожидали». Половина усилий по реализации этого принципа сводится к выбору хороших имен для компактных функций, выполняющих одну операцию. Чем меньше и специализированнее функция, тем проще выбрать для нее содержательное имя.

Не бойтесь использовать длинные имена. Длинное содержательное имя лучше короткого невразумительного. Выберите схему, которая позволяет легко прочитать слова в имени функции, а затем составьте из этих слов имя, которое описывает назначение функции.