Читать «Рефакторинг с использованием шаблонов» онлайн - страница 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).