Читать «Рефакторинг с использованием шаблонов» онлайн - страница 208

Джошуа Кериевски

public Loan(Capitalstrategy strategy, float notional,

float outstanding, int rating, Date expiry, Date maturity) ( this.strategy = strategy;

this.notional = notional;

this.outstanding = outstanding;

this.rating = rating;

this.expiry = expiry;

this.maturity = maturity;

}

Давайте посмотрим, что происходит с этим кодом при рефакторинге.

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

public Loan (float notional, float outstanding, int rating. Date expiry) {

this (new TermROCO, notional, outstanding, rating, expiry, null);

}

S Компиляция и тестирование проходят успешно.

2. Я повторяю шаг 1 для максимально возможного удаления дублирования. Это приводит меня к рассмотрению второго конструктора. Он также может вызывать третий конструктор.

public Loan (float notional, float outstanding, int rating, Date expiry. Date maturity) {

this(new RevolvingTermROC(), notional, outstanding, rating, expiry, maturity);

}

Теперь я знаю, что третий конструктор является всеохватывающим конструктором, поскольку он справляется со всей необходимой для создания объекта работой.

3. Я просматриваю код на предмет вызова всех трех конструкторов, чтобы выяснить, можно ли изменить их доступность. В данном случае я не могу этого сделать (поверьте мне на слово, так как перед вами нет кода, который вызывает эти конструкторы).

J Я компилирую и тестирую рефакторинг.

Unify Interfaces

Вам нужен надкласс и/или интерфейс с таким же интерфейсом, что и у подкласса.

Найдите все открытые методы, отсутствующие в надклассе/интерфейсе. Добавьте копии этих отсутствующих методов в надкласс, изменяя каждый таким образом, чтобы он ничего не делал.

Мотивация

Для полиморфной работы с объектами классы и объекты должны совместно использовать общий интерфейс — неважно, интерфейс надкласса или действительный интерфейс. Этот рефакторинг применим к случаю, когда надкласс или интерфейс должны иметь тот же интерфейс, что и подкласс.

Я столкнулся с необходимостью такого рефакторинга в двух разных ситуациях. Однажды, когда я применял Move Embellishment to Decorator (с. 174), выяснилось, что Decorator [12] требовал тот же интерфейс, что и у подкласса. Простейшим способом добиться этого было применение рефакторинга Unify Interfaces. Аналогично: при применении рефакторинга Move Accumulation to Visitor (с. 359) дублирование кода могло быть устранено, если бы определенные объекты использовали один и тот же интерфейс, что было возможно благодаря использованию рефакторинга Unify Interfaces.

После применения данного рефакторинга к надклассу и подклассу я иногда применяю к надклассу Extract Interface [15] для получения автономного интерфейса. Я обычно делаю это тогда, когда базовый класс содержит поля состояния и я не хочу, чтобы реализаторы общего базового класса, такие, как Decorator, наследовали эти поля. См. пример в описании Move Embellishment to Decorator (с. 174).