Экстремальное программирование. Разработка через тестирование | страница 28
Валюта?
Нужен ли тест testFrancMultiplication()?
Далее мы планируем перейти к устранению дублирования в методах times(). А сейчас вспомним, что в данной главе мы
• сделали шаг на пути к устранению дублирования – сформировали общую сигнатуру для двух вариантов одного метода – times();
• добавили объявление метода в общий суперкласс;
• освободили тестовый код от ссылок на производные классы, для этого были созданы фабричные методы;
• заметили, что, когда подклассы исчезли, некоторые тесты стали избыточными, однако никаких действий предпринято не было.
9. Потребность в валюте
$5 + 1 °CHF = $10, если курс обмена 2:1
$5 * 2 = $10
Сделать переменную amount закрытым (private) членом
Побочные эффекты в классе Dollar?
Округление денежных величин?
equals()
hashCode()
Равенство значению null
Равенство объектов
5 CHF * 2 = 1 °CHF
Дублирование Dollar/Franc
Общие операции equals()
Общие операции times()
Сравнение франков (Franc) и долларов (Dollar)
Валюта?
Нужен ли тест testFrancMultiplication()?
Есть ли в нашем списке задач какой-либо пункт, который помог бы нам избавиться от этих надоедливых подклассов? Что произойдет, если мы попробуем ввести в нашу программу понятие валюты?
Каким образом мы можем реализовать понятие валюты в данный момент? Черт! Опять я говорю ерунду! Вместо того чтобы снова бить себя линейкой по рукам, попробую перефразировать: каким образом мы можем протестировать понятие валюты в данный момент? Слава богу, мои руки спасены.
Возможно, в будущем нам захочется создать специальный класс валюты, применив шаблон «Приспособленец» (Flyweight Factory), чтобы избежать создания лишних объектов. Однако на текущий момент понятие валюты вполне можно реализовать в виде обычных строк:
public void testCurrency() {
assertEquals("USD", Money.dollar(1). currency());
assertEquals("CHF", Money.franc(1). currency());
}
Прежде всего объявим метод currency() в классе Money:
Money
abstract String currency();
Теперь реализуем этот метод в обоих подклассах:
Franc
String currency() {
return "CHF";
}
Dollar
String currency() {
return "USD";
}
Однако хотелось бы иметь одну и ту же реализацию в обоих подклассах, поэтому сохраним идентификатор валюты в специальном поле класса и просто вернем его значение в методе currency(). (Я начинаю делать рефакторинг быстрее, чтобы сэкономить время. Если вам покажется, что я рассказываю слишком быстро, не стесняйтесь попросить меня замедлиться. Постойте-ка, это же книга, – наверное, мне не стоит слишком уж ускоряться.)