Заздрісні функції

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до навігації Перейти до пошуку

Заздрісні функції (англ. Feature Envy) — один із «запахів коду», тобто код із ознаками проблем в системі. Суть «запаху» полягає у тому, що метод деякого об'єкту звертається до даних іншого об'єкту частіше, ніж до власних даних. Це призводить до надлишкової зв'язаності між класами.

Проблема[ред. | ред. код]

Customer втручається в дані Phone, щоб відформатувати число. «Запах» часто проявляється у вигляді недоречної відповідальності (приклад коду на Java):

public class Phone {
   private final String unformattedNumber;
   public Phone(String unformattedNumber) {
      this.unformattedNumber = unformattedNumber;
   }
   public String getAreaCode() {
      return unformattedNumber.substring(0,3);
   }
   public String getPrefix() {
      return unformattedNumber.substring(3,6);
   }
   public String getNumber() {
      return unformattedNumber.substring(6,10);
   }
}
public class Customer
   private Phone mobilePhone;
   public String getMobilePhoneNumber() {
      return "(" + 
         mobilePhone.getAreaCode() + ") " +
         mobilePhone.getPrefix() + "-" +
         mobilePhone.getNumber();
   }

Лікування[ред. | ред. код]

Слід дотримуватися такого правила: те, що змінюється разом, треба зберігати в одному місці. Зазвичай дані і функції, які використовують ці дані, також змінюються разом (хоча бувають виключення).

  • Якщо метод явно слід перенести в інше місце, застосуйте переміщення методу.
  • Якщо тільки частина методу звертається до даних іншого об'єкту, застосуйте відокремлення методу до цієї частини.
  • Якщо метод використовує функції декількох інших класів, треба спочатку визначити, в якому класі знаходиться найбільше даних, що використовуються. Потім слід перемістити метод в цей клас разом з іншими даними. Як альтернатива, за допомогою відокремлення методу метод розбивається на декілька частин, і вони розміщуються в різних частинах інших класів.

Належне лікування для попереднього прикладу:

public class Phone {
   private final String unformattedNumber;
   public Phone(String unformattedNumber) {
      this.unformattedNumber = unformattedNumber;
   }
   private String getAreaCode() {
      return unformattedNumber.substring(0,3);
   }
   private String getPrefix() {
      return unformattedNumber.substring(3,6);
   }
   private String getNumber() {
      return unformattedNumber.substring(6,10);
   }
   public String toFormattedString() {
      return "(" + getAreaCode() + ") " + getPrefix() + "-" + getNumber();
   }  
}
public class Customer
   private Phone mobilePhone;
   public String getMobilePhoneNumber() {
      return mobilePhone.toFormattedString();
   }

Переваги[ред. | ред. код]

  • Зменшення дублювання коду (якщо код обробки даних переїхав в одне загальне місце).
  • Поліпшення організації коду (оскільки методи роботи з даними знаходяться біля цих даних).

Випадки, коли застосувати не можна[ред. | ред. код]

Бувають випадки, коли поведінка навмисно відділяється від класу, що містить дані. Найчастіше це роблять для того, щоб мати можливість динамічно міняти цю поведінку (патерни Стратегія, Відвідувач і так далі).

Див. також[ред. | ред. код]

Посилання[ред. | ред. код]