Введение внешнего метода
Проблема
Служебный класс не содержит метода, который вам нужен, при этом у вас нет возможности добавить метод в этот класс.
Решение
Добавьте метод в клиентский класс и передавайте в него объект служебного класса в качестве аргумента.
class Report {
// ...
void sendReport() {
Date nextDay = new Date(previousEnd.getYear(),
previousEnd.getMonth(), previousEnd.getDate() + 1);
// ...
}
}
class Report {
// ...
void sendReport() {
Date newStart = nextDay(previousEnd);
// ...
}
private static Date nextDay(Date arg) {
return new Date(arg.getYear(), arg.getMonth(), arg.getDate() + 1);
}
}
class Report
{
// ...
void SendReport()
{
DateTime nextDay = previousEnd.AddDays(1);
// ...
}
}
class Report
{
// ...
void SendReport()
{
DateTime nextDay = NextDay(previousEnd);
// ...
}
private static DateTime NextDay(DateTime date)
{
return date.AddDays(1);
}
}
class Report {
// ...
public function sendReport() {
$previousDate = clone $this->previousDate;
$paymentDate = $previousDate->modify("+7 days");
// ...
}
}
class Report {
// ...
public function sendReport() {
$paymentDate = self::nextWeek($this->previousDate);
// ...
}
/**
* Foreign method. Should be in Date.
*/
private static function nextWeek(DateTime $arg) {
$previousDate = clone $arg;
return $previousDate->modify("+7 days");
}
}
class Report:
# ...
def sendReport(self):
nextDay = Date(self.previousEnd.getYear(),
self.previousEnd.getMonth(), self.previousEnd.getDate() + 1)
# ...
class Report:
# ...
def sendReport(self):
newStart = self._nextDay(self.previousEnd)
# ...
def _nextDay(self, arg):
return Date(arg.getYear(), arg.getMonth(), arg.getDate() + 1)
class Report {
// ...
sendReport(): void {
let nextDay: Date = new Date(previousEnd.getYear(),
previousEnd.getMonth(), previousEnd.getDate() + 1);
// ...
}
}
class Report {
// ...
sendReport() {
let newStart: Date = nextDay(previousEnd);
// ...
}
private static nextDay(arg: Date): Date {
return new Date(arg.getFullYear(), arg.getMonth(), arg.getDate() + 1);
}
}
Причины рефакторинга
У вас есть код, который использует данные и методы определённого класса. Вы приходите к выводу, что этот код намного лучше будет смотреться и работать внутри нового метода в этом классе. Однако возможность добавить такой метод в класс у вас отсутствует (например, потому что класс находится в сторонней библиотеке).
Данный рефакторинг особенно выгоден в случаях, когда участок кода, который вы хотите перенести в метод, повторяется несколько раз в различных местах программы.
Так как вы передаёте объект служебного класса в параметры нового метода, у вас есть доступ ко всем его полям. Вы можете делать внутри этого метода практически все, что вам может потребоваться, как если бы метод был частью служебного класса.
Достоинства
- Убирает дублирование кода. Если ваш участок кода повторяется в нескольких местах, вы можете заменить их вызовом метода. Это удобнее дублирования даже с учетом того, что внешний метод находится не там, где хотелось бы.
Недостатки
- Причины того, почему метод служебного класса находится в клиентском классе, не всегда очевидны для того специалиста, который будет поддерживать код после вас. Если данный метод может быть использован и в других классах, имеет смысл создать обёртку над служебным классом, и поместить метод туда. То же самое имеет смысл сделать, если таких служебных методов несколько. В этом поможет рефакторинг введение локального расширения.
Порядок рефакторинга
-
Создайте новый метод в клиентском классе.
-
В этом методе создайте параметр, в который будет передаваться объект служебного класса. Если этот объект может быть получен из клиентского класса, параметр можно не создавать.
-
Извлеките волнующие вас участки кода в этот метод и замените их вызовами метода.
-
Обязательно оставьте в комментарии к этому методу метку Foreign method и призыв поместить этот метод в служебный класс, если такая возможность появится в дальнейшем. Это облегчит понимание того, почему этот метод находится в данном классе для тех, кто будет поддерживать программный продукт в будущем.