5. Поговорим о франках
$5 + 1 °CHF = $10, если курс обмена 2:1
$5 * 2 = $10
Сд елать переменную amount закрытым (private) членом
Побочные эффекты в классе Dollar?Округление д енежных величин?
equals()
hashCode()
Равенство значению null
Равенство объектов
5 CHF * 2 = 1 °CHF
Можем ли мы приступить к реализации первого, самого
интересного теста в д анном списке? Мне все еще кажется, что это буд ет
слишком большой шаг. Я не пред ставляю себе, как можно написать этот
тест за од ин маленький шажок. Мне кажется, что вначале необход имо
созд ать объект напод обие Dollar, который соответствовал бы не
д олларам, а франкам. Пусть это буд ет объект с названием Franc. Для
начала объект Franc может функционировать в точно сти как объект
Dollar – если у нас буд ет такой объект, нам буд ет проще размышлять о
реализации теста, связанного со смешанным сложением д вух разных
валют.
А если объект Franc работает так же, как объект Dollar, значит, мы
можем про сто скопировать и слегка отред актировать тест д ля объекта
Dollar:
public void testFrancMultiplication() {
Franc five = new Franc(5);
assertEquals(new Franc(10), five.times(2));
assertEquals(new Franc(15), five.times(3));
}
(Хорошо, что в главе 4 мы упро стили тест д ля Dollar. Благод аря
этому работа по ред актированию теста существенно упро стилась.
Похоже, в д анной книге д ела ид ут д овольно глад ко, од нако я не могут
гарантировать, что в буд ущем все буд ет так же хорошо.)
Теперь нам над о получить зеленую поло ску. Какой спо соб буд ет
самым про стым? Проще всего скопировать код класса Dollar и заменить
Dollar на Franc.
Стоп. Под ожд ите-ка. Я уже вижу, как некоторые наиболее ярые
сторонники правильных под ход ов начинают морщиться и плеваться.
Повторное использование код а путем его д ублирования через буфер
обмена? Пренебрежение абстракцией? А как же все эти разговоры об
о сновополагающих принципах ООП и чистом д изайне?
Если вам не по себе, глубоко вд охните через но с, д о считайте д о
трех и мед ленно выд охните через рот. Вам лучше? Теперь вспомните,
что наш цикл со стоит из пяти этапов. Иногд а по след овательное
выполнение всех этапов занимает всего несколько секунд , од нако в
любом случае мы обязательно выполняем кажд ый из них:
1. Написать тест.
2. Добиться его безошибочной компиляции.
3. Запустить тест и убед иться, что он потерпел неуд ачу.
4. Добиться успешного выполнения теста.
5. Устранить д ублирование.
На разных этапах решаются разные зад ачи, преслед уются разные
цели. То, что совершенно нед опустимо д ля од ного из этапов, может
быть вполне приемлемым д ля д ругого этапа. Од нако в целом метод ика
TDD работает только в случае, если ни од ин из этапов не упущен. Если
вы пропустите хотя бы од но звено, развалится вся цепочка.
Первые три фазы цикла разработки TDD д олжны выполняться как
можно быстрее. Опред еляющая характеристика этих этапов – скоро сть.
На этих этапах в жертву скоро сти можно принести очень многое, в том
числе чистоту д изайна. Честно говоря, сейчас я несколько волнуюсь. Я
только что разрешил вам забыть о принципах хорошего д изайна.
Пред ставляю, как вы приход ите к своим коллегам, под чиненным и во
всеуслышание объявляете: «Кент сказал, что все эти разговоры про
хороший д изайн – полная ерунд а!» Остановитесь. Цикл еще не закончен.
Четырехногий урод ец из благород ного семейства пятиногих стульев
вечно пад ает. Первые четыре шага нашего цикла не работают без пятого.
Хороший д изайн в под ход ящее время! Сначала сд елаем, чтобы код
заработал, потом сд елаем, чтобы код был правильным (make it run, make
it right).
Теперь мне стало легче. Теперь я уверен, что д о тех пор, пока вы не
избавитесь от д ублирования, вы не покажете свой код никому за
исключением своего партнера по паре. На чем мы о становились? Ах, д а.
Забываем о принципах хорошего д изайна в угод у скоро сти (мы буд ем
заниматься искуплением этого греха на протяжении нескольких
след ующих глав).
Franc
class Franc {
private int amount;
Franc(int amount) {
this.amount = amount;
}
Franc times(int multiplier) {
return new Franc(amount * multiplier);
}
public boolean equals(Object object) {
Franc franc = (Franc) object;
return amount == franc.amount;
}
}
$5 + 1 °CHF = $10, если курс обмена 2:1
$5 * 2 = $10
Сд елать переменную amount закрытым (private) членом
Побочные эффекты в классе Dollar?
Округление д енежных величин?
equals()
hashCode()
Равенство значению null
Равенство объектов
5 CHF * 2 = 1 °CHF
Дублирование Dollar/Franc
Общие операции equals()
Общие операции times()
Чтобы запустить код , нам не потребовало сь приклад ывать каких-
либо усилий, поэтому мы смогли «перепрыгнуть» через этап «д обиться
безошибочной компиляции код а» (Make it compile).
Зато теперь в нашем код е полно повторяющихся фрагментов.
Прежд е чем приступить к разработке след ующего теста, мы д олжны
избавиться от д ублирования. Думаю, что след ует начать с обобщения
метод а equals(). Од нако об этом в след ующей главе. На текущий момент
мы можем вычеркнуть из нашего списка еще од ин пункт, од нако вместе
с этим нам прид ется д обавить в него д ва д ополнительных пункта.
В д анной главе мы
• решили отказаться от созд ания слишком большого теста и вместо
этого созд али маленький, чтобы обеспечить быстрый прогресс;
• созд али код теста путем бесстыд ного копирования и
ред актирования;
• хуже того, д обились успешного выполнения теста путем
копирования и ред актирования разработанного ранее код а;
• д али себе обещание ни в коем случае не уход ить д омой д о тех пор,
пока не устраним д ублирование.
Do'stlaringiz bilan baham: |