Читаем Экстремальное программирование: Разработка через тестирование полностью

Money

public Money reduce(String to) {

int rate = (currency.equals("CHF") && to.equals("USD"))

? 2

: 1;

return new Money(amount / rate, to);

}

Получается, что класс Money знает о курсе обмена. Это неправильно. Единственным местом, в котором выполняются любые операции, связанные с курсом обмена, должен быть класс Bank. Мы должны передать параметр типа Bank в метод Expression.reduce(). (Вот видите? Мы так и думали, что нам это потребуется. И мы оказались правы.) Вначале меняем вызывающий код:

Bank

Money reduce(Expression source, String to) {

return source.reduce(this, to);

}

Затем меняем код реализаций:

Expression

Money reduce(Bank bank, String to);

Sum

public Money reduce(Bank bank, String to) {

int amount = augend.amount + addend.amount;

return new Money(amount, to);

}

Money

public Money reduce(Bank bank, String to) {

int rate = (currency.equals("CHF") && to.equals("USD"))

? 2

: 1;

return new Money(amount / rate, to);

}

Методы должны быть общедоступными (public), так как все методы интерфейсов должны быть общедоступными (я надеюсь, можно не объяснять, почему).

Теперь мы можем вычислить курс обмена внутри класса Bank:

Bank

int rate(String from, String to) {

return (from.equals("CHF") && to.equals("USD"))

? 2

: 1;

}

И обратиться к объекту bank с просьбой предоставить значение курса обмена:

Money

public Money reduce(Bank bank, String to) {

int rate = bank.rate(currency, to);

return new Money(amount / rate, to);

}

Эта надоедливая цифра 2 снова отсвечивает как в разрабатываемом коде, так и в теле теста. Чтобы избавиться от нее, мы должны создать таблицу обменных курсов в классе Bank и при необходимости обращаться к этой таблице для получения значения обменного курса. Для этой цели мы могли бы воспользоваться хеш-таблицей, которая ставит в соответствие паре валют соответствующий обменный курс. Можем ли мы в качестве ключа использовать двухэлементный массив, содержащий в себе две валюты? Проверяет ли метод Array.equals() эквивалентность элементов массива?

public void testArrayEquals() {

assertEquals(new Object[] {"abc"}, new Object[] {"abc"});

}

Нет. Тест провалился. Придется создавать специальный объект, который будет использоваться в качестве ключа хеш-таблицы:

Pair

private class Pair {

private String from;

private String to;

Pair(String from, String to) {

this.from = from;

this.to = to;

}

}

Мы планируем использовать объекты Pair в качестве ключей, поэтому нам необходимо реализовать методы equals() и hashCode(). Я не собираюсь писать для этого тесты, так как мы разрабатываем код в контексте рефакторинга. Дело в том, что от работоспособности этого кода жестко зависит успешное выполнение существующих тестов. Если код работает неправильно, существующие тесты потерпят неудачу. Однако если бы я программировал в паре с кем-то, кто плохо представлял бы себе направление дальнейшего движения, или если бы логика кода была более сложной, я несомненно приступил бы к разработке специальных тестов.

Pair

public boolean equals(Object object) {

Pair pair = (Pair) object;

return from.equals(pair.from) && to.equals(pair.to);

}

public int hashCode() {

return 0;

}

0 – ужасное хеш-значение, однако такой метод хеширования легко реализовать, стало быть, мы быстрее получим работающий код. Поиск валюты будет осуществляться простым линейным перебором. Позже, когда у нас будет множество валют, мы сможем тщательнее проработать этот вопрос, использовав реальные данные.

Теперь нам нужно место, в котором мы могли бы хранить значения обменных курсов:

Bank

private Hashtable rates= new Hashtable();

Нам также потребуется метод добавления нового курса обмена:

Bank

void addRate(String from, String to, int rate) {

rates.put(new Pair(from, to), new Integer(rate));

}

И метод, возвращающий обменный курс:

Bank

int rate(String from, String to) {

Integer rate = (Integer) rates.get(new Pair(from, to));

return rate.intValue();

}

Подождите-ка минутку! Перед нами красная полоса. Что случилось? Взглянув на код, мы видим, что проблема в неправильном значении курса при обмене доллара на доллары. Мы ожидаем, что при обмене USD на USD курс обмена будет равен 1, однако на текущий момент это не так. Поскольку эта ситуация стала для нас сюрпризом, оформим ее в виде дополнительного теста:

public void testIdentityRate() {

assertEquals(1, new Bank(). rate("USD", "USD"));

}

Теперь у нас три ошибки, однако все они могут быть исправлены при помощи одного небольшого изменения:

Bank

int rate(String from, String to) {

if (from.equals(to)) return 1;

Integer rate = (Integer) rates.get(new Pair(from, to));

return rate.intValue();

}

Зеленая полоска!

$5 + 1 °CHF = $10, если курс обмена 2:1

$5 + $5 = $10

Операция $5 + $5 возвращает объект Money

Bank.reduce(Money)

Приведение объекта Money с одновременной конверсией валют

Reduce(Bank,String)

Перейти на страницу:

Все книги серии Библиотека программиста

Программист-фанатик
Программист-фанатик

В этой книге вы не найдете описания конкретных технологий, алгоритмов и языков программирования — ценность ее не в этом. Она представляет собой сборник практических советов и рекомендаций, касающихся ситуаций, с которыми порой сталкивается любой разработчик: отсутствие мотивации, выбор приоритетов, психология программирования, отношения с руководством и коллегами и многие другие. Подобные знания обычно приходят лишь в результате многолетнего опыта реальной работы. По большому счету перед вами — ярко и увлекательно написанное руководство, которое поможет быстро сделать карьеру в индустрии разработки ПО любому, кто поставил себе такую цель. Конечно, опытные программисты могут найти некоторые идеи автора достаточно очевидными, но и для таких найдутся темы, которые позволят пересмотреть устоявшиеся взгляды и выйти на новый уровень мастерства. Для тех же, кто только в самом начале своего пути как разработчика, чтение данной книги, несомненно, откроет широчайшие перспективы. Издательство выражает благодарность Шувалову А. В. и Курышеву А. И. за помощь в работе над книгой.

Чед Фаулер

Программирование, программы, базы данных / Программирование / Книги по IT

Похожие книги