Введення зовнішнього методу
Проблема
Службовий клас не містить методу, який вам потрібен, при цьому у вас немає можливості додати метод в цей клас.
Рішення
Додайте метод в клієнтський клас і передавайте в нього об’єкт службового класу в якості аргументу.
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);
}
}
Причини рефакторингу
У вас є код, який використовує дані і методи певного класу. Ви робите висновок, що цей код набагато краще буде виглядати і працювати всередині нового методу в цьому класі. Проте можливості додати такий метод в клас у вас немає (наприклад, тому що клас знаходиться в сторонній бібліотеці).
Цей рефакторинг найвигідніше використовувати у випадках, коли ділянка коду, який ви хочете перенести в метод, повторюється кілька разів в різних місцях програми.
Оскільки ви передаєте об’єкт службового класу в параметри нового методу, у вас є доступ до всіх його полів. Ви можете робити всередині цього методу практично все, що вам може бути потрібно, начебто метод є частиною службового класу.
Переваги
- Прибирає дублювання коду. Якщо ваша ділянка коду повторюється в декількох місцях, ви можете замінити її викликом методу. Це зручніше за дублювання навіть з урахуванням того, що зовнішній метод знаходиться не там, де б хотілось.
Недоліки
- Причини того, чому метод службового класу знаходиться в клієнтському класі не завжди очевидні для того фахівця, який підтримуватиме код після вас. Якщо цей метод може бути використаний і в інших класах, має сенс створити обгортку над службовим класом, і помістити метод туди. Те ж саме має сенс зробити, якщо таких службових методів декілька. У цьому допоможе рефакторинг введення локального розширення.
Порядок рефакторингу
-
Створіть новий метод в клієнтському класі.
-
У цьому методі створіть параметр, в який передаватиметься об’єкт службового класу. Якщо цей об’єкт може бути отриманий з клієнтського класу, параметр можна не створювати.
-
Витягніть ділянки коду, які вам потрібні, в цей метод і замініть їх викликами методу.
-
Обов’язково залиште в коментарі до цього методу мітку Foreight method і заклик перенести цей метод в службовий клас, якщо така можливість з’явиться надалі. Це полегшить розуміння того, чому метод знаходиться в цьому класі для тих, хто підтримуватиме програмний продукт в майбутньому.