Продолжая использовать наш сайт, вы даете согласие на обработку файлов cookie, которые обеспечивают правильную работу сайта. Благодаря им мы улучшаем сайт!
Принять и закрыть

Читать, слущать книги онлайн бесплатно!

Электронная Литература.

Бесплатная онлайн библиотека.



Главная
Все книги
Назад
Читать: Экстремальное программирование. Разработка через тестирование - Кент Бек на бесплатной онлайн библиотеке Э-Лит


Помоги проекту - поделись книгой:

Dollar

public boolean equals(Object object) {

Money dollar = (Dollar) object;

return amount == dollar.amount;

}

Все тесты по-прежнему работают. Теперь попробуем изменить приведение типа.

Dollar

public boolean equals(Object object) {

Money dollar = (Money) object;

return amount == dollar.amount;

}

Чтобы исходный код получился более осмысленным, изменим имя временной переменной:

Dollar

public boolean equals(Object object) {

Money money = (Money) object;

return amount == money.amount;

}

Теперь переместим метод из класса Dollar в класс Money:

Money

public boolean equals(Object object) {

Money money= (Money) object;

return amount == money.amount;

}

Теперь настало время удалить метод Franc.equals(). Прежде всего мы обнаруживаем, что у нас до сих пор нет теста, проверяющего равенство двух объектов класса Franc, – когда мы, особо не раздумывая, дублировали код класса Dollar, мы нагрешили еще больше, чем думали. Поэтому, прежде чем модифицировать код, мы должны написать все необходимые тесты.

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

Прежде чем что-либо менять в коде, вы должны написать все тесты, которые кажутся вам необходимыми. Если этого не сделать, рано или поздно, выполняя рефакторинг, вы чего-нибудь поломаете. Код перестанет работать так, как должен. Вы потратите кучу времени на поиск ошибки и сформируете предубеждение против рефакторинга. Если подобный инцидент повторится, вы можете вообще перестать делать рефакторинг. Дизайн начнет деградировать. Вас уволят с работы. От вас уйдет ваша любимая собака. Вы перестанете мыться и чистить зубы. У вас начнется кариес. Чтобы сохранить зубы здоровыми, всегда сначала пишите тесты и только после этого выполняйте рефакторинг.

К счастью, в нашем случае написать тесты совсем несложно. Для этого достаточно скопировать и немножко отредактировать тесты для класса Dollar:

public void testEquality() {

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

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

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

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

}

Снова дублирование. Целых две строчки! Этот грех нам тоже придется искупить. Но чуть позже.

Теперь, когда тесты на месте, мы можем сделать класс Franc производным от класса Money:

Franc

class Franc extends Money {

private int amount;

}

Далее мы можем уничтожить поле amount в классе Franc, так как это значение будет храниться в одноименном поле класса Money:

Franc

class Franc extends Money {

}

Метод Franc.equals() выглядит фактически так же, как и метод Money.equals(). Сделав их абсолютно одинаковыми, мы сможем удалить реализацию этого метода из класса Franc. При этом смысл нашей программы не изменится. Для начала изменим объявление временной переменной:

Franc

public boolean equals(Object object) {

Money franc = (Franc) object;

return amount == franc.amount;

}

После этого изменим операцию преобразования типа:

Franc

public boolean equals(Object object) {

Money franc = (Money) object;

return amount == franc.amount;

}

Теперь, даже не меняя имя временной переменной, можно видеть, что метод получился фактически таким же, как одноименный метод в классе Money. Однако для пущей уверенности переименуем временную переменную:

Franc

public boolean equals(Object object) {

Money money = (Money) object;

return amount == money.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)

Теперь нет никакой разницы между методами Franc.equals() и Money.equals(), и мы можем удалить избыточную реализацию этого метода из класса Franc. Запускаем тесты. Они выполняются успешно.

Что должно происходить при сравнении франков и долларов? Мы рассмотрим этот вопрос в главе 7.

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

• поэтапно переместили общий код из одного класса (Dollar) в суперкласс (Money);



Поделиться книгой:



Регистрация