Экстремальное программирование. Разработка через тестирование | страница 26



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

• добились успешного выполнения теста приемлемым, но не идеальным способом – 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():