Autumn SALE

Заміна методу об'єктом методів

Також відомий як: Replace Method with Method Object

Проблема

У вас є довгий метод, в якому локальні змінні так сильно переплетені, що це робить неможливим застосування відокремлення методу.

Рішення

Перетворіть метод в окремий клас так, щоб локальні змінні стали полями цього класу. Після цього можна без проблем розділити метод на частини.

До
class Order { // ... public double price() { double primaryBasePrice; double secondaryBasePrice; double tertiaryBasePrice; // Perform long computation. } }
Після
class Order { // ... public double price() { return new PriceCalculator(this).compute(); } } class PriceCalculator { private double primaryBasePrice; private double secondaryBasePrice; private double tertiaryBasePrice; public PriceCalculator(Order order) { // Copy relevant information from the // order object. } public double compute() { // Perform long computation. } }
До
public class Order { // ... public double Price() { double primaryBasePrice; double secondaryBasePrice; double tertiaryBasePrice; // Perform long computation. } }
Після
public class Order { // ... public double Price() { return new PriceCalculator(this).Compute(); } } public class PriceCalculator { private double primaryBasePrice; private double secondaryBasePrice; private double tertiaryBasePrice; public PriceCalculator(Order order) { // Copy relevant information from the // order object. } public double Compute() { // Perform long computation. } }
До
class Order { // ... public function price() { $primaryBasePrice = 10; $secondaryBasePrice = 20; $tertiaryBasePrice = 30; // Perform long computation. } }
Після
class Order { // ... public function price() { return (new PriceCalculator($this))->compute(); } } class PriceCalculator { private $primaryBasePrice; private $secondaryBasePrice; private $tertiaryBasePrice; public function __construct(Order $order) { // Copy relevant information from the // order object. } public function compute() { // Perform long computation. } }
До
class Order: # ... def price(self): primaryBasePrice = 0 secondaryBasePrice = 0 tertiaryBasePrice = 0 # Perform long computation.
Після
class Order: # ... def price(self): return PriceCalculator(self).compute() class PriceCalculator: def __init__(self, order): self._primaryBasePrice = 0 self._secondaryBasePrice = 0 self._tertiaryBasePrice = 0 # Copy relevant information from the # order object. def compute(self): # Perform long computation.
До
class Order { // ... price(): number { let primaryBasePrice; let secondaryBasePrice; let tertiaryBasePrice; // Perform long computation. } }
Після
class Order { // ... price(): number { return new PriceCalculator(this).compute(); } } class PriceCalculator { private _primaryBasePrice: number; private _secondaryBasePrice: number; private _tertiaryBasePrice: number; constructor(order: Order) { // Copy relevant information from the // order object. } compute(): number { // Perform long computation. } }

Причини рефакторингу

Метод занадто довгий, і ви не можете його розділити через переплетення локальних змінних, які складно ізолювати одну від одної.

Першим кроком до вирішення проблеми буде виділення всього цього методу в окремий клас і перетворення його локальних змінних на поля.

По-перше, це дозволить вам ізолювати проблему в межах цього класу, а по-друге, розчистить дорогу для розділення великого методу на менші за розміром методи, які, до того ж, не підходили б до контексту оригінального класу.

Переваги

  • Ізоляція довгого методу у власному класі дозволяє зупинити безконтрольне зростання методу. Крім того, дає можливість ділити його на підметоди в рамках свого класу, не засмічуючи службовими методами оригінальний клас.

Недоліки

  • Створюється ще один клас, підвищуючи загальну складність програми.

Порядок рефакторингу

  1. Створіть новий клас. Дайте йому назву, ґрунтуючись на призначенні методу, над яким проводиться рефакторинг.

  2. У новому класі створіть приватне поле для зберігання посилання на екземпляр класу, в якому раніше знаходився метод. Це посилання згодом можна використати, щоб взяти з оригінального об’єкта якісь допоміжні дані.

  3. Створіть окреме приватне поле для кожної локальної змінної методу.

  4. Створіть конструктор, який приймає в параметрах значення всіх локальних змінних методу, а також ініціалізує відповідні приватні поля.

  5. Оголосіть основний метод і скопіюйте в нього код оригінального методу, замінивши локальні змінні приватними полями.

  6. Замініть тіло оригінального методу в початковому класі створенням об’єкта-методу і викликом його основного методу.