Заздрісні функції (англ. 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();
   }

Переваги ред.

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

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

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

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

Посилання ред.