Информационный сайт

 

Реклама
bulletinsite.net -> Книги на сайте -> Программисту -> Бек К. -> "Экстремальное программирование: разработка через тестирование " -> 24

Экстремальное программирование: разработка через тестирование - Бек К.

Бек К. Экстремальное программирование: разработка через тестирование — СПб.: Питер, 2003. — 224 c.
ISBN 5-8046-0051-6
Скачать (прямая ссылка): bek-k..pdf
Предыдущая << 1 .. 18 19 20 21 22 23 < 24 > 25 26 27 28 29 30 .. 81 >> Следующая


public void testReduceSumO {

Expression sum= new Sum(Money.dollar(3). Money.dollar(4)):

Bank, bank= new BankO:

Money result= bank.reduce(sum. "USD"):

assertEquals(Money.dollar(7). result);

}

Я тщательно выбираю значения параметров таким образом, чтобы нарушить работу существующего теста. Когда мы приводим (метод reduce()) объект класса Sum к некоторой валюте, в результате (с учетом упомянутых упрощенных условий) должен получиться объект класса Money, чье значение (amount) совпадает с суммой значений двух объектов Money, переданных конструктору объекта Sum, а валюта (currency) совпадает с валютой обоих этих объектов:

Bank

Money reduce(Expression source. String to) {

Sum sum= (Sum) source;

int amount= sum.augend.amount + sum.addend.amount: return new Money(amount, to);

}

Код выглядит уродливо по двум причинам:

• мы выполняем приведение типов (к типу Sum), в то время как код должен работать с любым объектом типа Expression;

• мы используем открытые поля и два уровня ссылок на поля объектов. Это достаточно легко исправить. Вначале переместим тело метода в класс Sum

и благодаря этому избавимся от лишнего уровня ссылок.

Bank

Money reduce(Expression source. String to) { Sum sum= (Sum) source: return sum.reduce(to);

}

Sum ,

public Money reduce(String to) {

int amount- augend.amount + addend.amount;

return new Money(amount, to):

}

На секундочку заглянем в будущее. Приведение (reduce) суммы к некоторой валюте не может быть выполнено, если объект Sum не знает об обменном курсе. Однако обменный курс хранится в классе Bank, значит, скорее всего, в будущем нам потребуется передавать в метод Sum.reduceQ еще один параметр типа Bank. Однако сейчас наш код не требует этого. Поэтому мы не добавляем никаких лишних параметров, чтобы лишний раз в них не путаться. (Что касается меня, то искушение было столь велико, что я все-таки добавил этот параметр, когда в первый раз писал данный код, — мне очень, очень стыдно.)

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

Операция $5 + $5 возвращает объект Money : Bank.reduce(Money)

Так, а что же происходит в случае* если аргументом метода Bank.reduce() является объект Money?

Давайте напишем тест, слава богу, перед нами зеленая полоса и мы не видим каких-либо других очевидных способов модификации кода:

public void testReduceMoneyO { Bank bank= new BankO;

Money result= bank.reduce(Money.dollard). "USD"); assertEquals(Money.dollar(l), result);

}

Bank

Money reducetExpression source. String to) {

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;

Глава 13 • Делаем реализацию реальной 75

Включаем метод 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 + 10 CHF = $10, если курс обмена 2:1 $5 + $5 = $10

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

Приведение объекта Money с одновременной конверсией валют Reduce(Bank,String)

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

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

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

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

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

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

• реализовали код с приведением типов в одном месте, добились срабатывания тестов, а затем переместили код туда, где он должен находиться;
Предыдущая << 1 .. 18 19 20 21 22 23 < 24 > 25 26 27 28 29 30 .. 81 >> Следующая
Реклама
Авторские права © 2009 AdsNet. Все права защищены.
Rambler's Top100