на текущий момент в нашей программе еще нет ничего, что соответствовало бы финансовому понятию «валюта», и пока я не вижу достаточно весомой причины, чтобы вводить в программу подобное понятие. Поэтому пока оставим код таким, какой он есть.

$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)

Валюта?

Теперь пришла пора избавиться от дублирующегося кода в методах times(), после этого мы сможем перейти к реализации смешанной валютной арифметики. Однако прежде, чем двинуться дальше, подведем итоги данной главы:

• мы превратили мучающее нас сомнение в тест;

• добились успешного выполнения теста приемлемым, но не идеальным способом – getClass();

• решили не добавлять в программу дополнительной логики, пока у нас не появится более весомая мотивация.

8. Создание объектов

$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)

Валюта?

Две разные реализации метода times() выглядят на удивление похоже:

Franc

Franc times(int multiplier) {

return new Franc(amount * multiplier)

}

Dollar

Dollar times(int multiplier) {

return new Dollar(amount * multiplier)

}

Мы можем сделать их еще более похожими, изменив тип возвращаемого значения на Money:

Franc

Money times(int multiplier) {

return new Franc(amount * multiplier)

}

Dollar

Money times(int multiplier) {

return new Dollar(amount * multiplier)

}

Следующий шаг менее очевиден. Два подкласса, производных от класса Money, мало чем отличаются друг от друга. Возникает желание избавиться от них. Однако мы не можем сделать это за один большой шаг, так как это нельзя будет назвать наглядной демонстрацией методики TDD.

Но что же делать? Полагаю, мы сможем приблизиться к решению задачи об уничтожении подклассов, если избавимся от прямых ссылок на подклассы. Для этого мы можем добавить в класс Money фабричный метод, который возвращал бы объект класса Dollar. Этот метод можно было бы использовать следующим образом:

public void testMultiplication() {

Dollar five = Money.dollar(5);

assertEquals(new Dollar(10), five.times(2));

assertEquals(new Dollar(15), five.times(3));

}

Реализация этого метода создает объект класса Dollar и возвращает его:

Money

static Dollar dollar(int amount) {

return new Dollar(amount);

}

Однако мы хотим избавиться от ссылок на Dollar, поэтому изменим объявление переменной в коде теста:

public void testMultiplication() {

Money five = Money.dollar(5);

assertEquals(new Dollar(10), five.times(2));

assertEquals(new Dollar(15), five.times(3));

}

Компилятор вежливо сообщает нам, что метод times() в классе Money не определен. На текущий момент мы не можем реализовать его, поэтому объявим класс Money абстрактным (может быть, с этого стоило начать?) и объявим также абстрактным метод Money.times():

Money

abstract class Money

abstract Money times(int multiplier);

Теперь мы можем изменить объявление фабричного метода:

Money

static Money dollar(int amount) {

return new Dollar(amount);

}

Все тесты выполняются успешно, стало быть, по крайней мере, мы ничего не сломали. Теперь мы можем использовать фабричный метод повсюду в тестах:

public void testMultiplication() {

Money five = Money.dollar(5);

assertEquals(Money.dollar(10), five.times(2));

assertEquals(Money.dollar(15), five.times(3));

}

public void testEquality() {

assertTrue(Money.dollar(5). equals(Money.dollar(5)));

assertFalse(Money.dollar(5). equals(Money.dollar(6)));

assertTrue(new Franc(5). equals(new Franc(5)));

assertFalse(new Franc(5). equals(new Franc(6)));

assertFalse(new Franc(5). equals(Money.dollar(5)));

}

Теперь мы находимся в несколько более выгодной позиции, чем раньше. Клиентский код ничего не знает о существовании подкласса Dollar. Освободив код тестов от ссылок на подклассы, мы получили возможность изменять структуру наследования, не внося при этом каких-либо изменений в клиентский код.

Прежде чем механически исправлять код теста testFrancMultiplication(), обратите внимание, что теперь он не тестирует никакой логики, кроме той, что уже протестирована функцией testMultiplication(). Напрашивается вопрос: нужна ли нам функция testFrancMultiplication()? Если мы удалим этот тест, потеряем ли мы уверенность в нашем коде? Похоже, что нет, однако мы все же сохраним пока этот тест просто так – на всякий случай.

public void testEquality() {

assertTrue(Money.dollar(5). equals(Money.dollar(5)));

assertFalse(Money.dollar(5). equals(Money.dollar(6)));

assertTrue(Money.franc(5). equals(Money.franc(5)));

assertFalse(Money.franc(5). equals(Money.franc(6)));

assertFalse(Money.franc(5). equals(Money.dollar(5)));

}

public void testFrancMultiplication() {

Money five = Money.franc(5);

assertEquals(Money.franc(10), five.times(2));

assertEquals(Money.franc(15), five.times(3));

}

Реализация метода Money.franc() почти такая же, как и реализация метода Money.dollar():

Money

static Money franc(int amount) {

return new 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()

Сравнение франков (Franc) и долларов (Dollar)

Валюта?

Нужен ли тест testFrancMultiplication()?

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату