Экстремальное программирование. Разработка через тестирование | страница 41



if (source instanceof Money) return (Money) source;

Sum sum= (Sum) source;

return sum.reduce(to);

}


Какой кошмар! Отвратительно! Тем не менее мы получили зеленую полоску и можем приступать к рефакторингу. Прежде всего, вместо прямой проверки класса всегда следует использовать полиморфизм. Класс Sum реализует метод reduce(String), и, если этот метод добавить в класс Money, мы сможем включить reduce(String) в состав интерфейса Expression.


Bank

Money reduce(Expression source, String to) {

if (source instanceof Money)

return (Money) source.reduce(to);

Sum sum = (Sum) source;

return sum.reduce(to);

}


Money

public Money reduce(String to) {

return this;

}


Включаем метод reduce(String) в состав интерфейса Expression:


Expression

Money reduce(String to);


Теперь можно избавиться от этих уродливых операций приведения типа и проверок классов:


Bank

Money reduce(Expression source, String to) {

return source.reduce(to);

}


Я не вполне доволен ситуацией, когда в интерфейсе Expression и классе Bank присутствуют методы с одинаковыми именами, но с разным набором параметров. Я так и не смог найти приемлемого решения этой проблемы в Java. В языках, где поддерживаются ключевые параметры, разница между методами Bank.reduce(Expression, String) и Expression.reduce(String) делается очевидной благодаря синтаксису языка. Однако в языках, в которых различие параметров определяется различием их позиций в списке параметров, разница между двумя подобными методами становится менее очевидной.


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

$5 + $5 = $10

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

Bank.reduce(Money)

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

Reduce(Bank,String)


Теперь можно приступить к задаче реального обмена одной валюты на другую.

В данной главе мы

• не отметили тест как завершенный, так как не избавились от дублирования;

• чтобы прояснить реализацию, решили двигаться вперед вместо того, чтобы двигаться назад;

• написали тест, чтобы форсировать создание объекта, который, как нам кажется, потребуется в будущем (объект класса Sum);

• ускорили процесс реализации (конструктор класса Sum);

• реализовали код с приведением типов в одном месте, добились успешного выполнения тестов, а затем переместили код туда, где он должен находиться;

• использовали полиморфизм, чтобы избавиться от явной проверки типа (класса).

14. Обмен валюты

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

$5 + $5 = $10

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