Экстремальное программирование. Разработка через тестирование | страница 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