🎉 Потрібна крута книжка про патерни та ще й українською? Ось вона »

Самоінкапсуляція поля

Також відомий як: Self Encapsulate Field

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

Проблема

Ви використовуєте прямий доступ до приватних полів усередині класу.

Рішення

Створіть геттер і сеттер для поля, і користуйтеся для доступу до поля тільки ними.

До
class Range {
  private int low, high;
  boolean includes(int arg) {
    return arg >= low && arg <= high;
  }
}
Після
class Range {
  private int low, high;
  boolean includes(int arg) {
    return arg >= getLow() && arg <= getHigh();
  }
  int getLow() {
    return low;
  }
  int getHigh() {
    return high;
  }
}
До
class Range 
{
  private int low, high;
  
  bool Includes(int arg) 
  {
    return arg >= low && arg <= high;
  }
}
Після
class Range 
{
  private int low, high;
  
  int Low {
    get { return low; }
  }
  int High {
    get { return high; }
  }
  
  bool Includes(int arg) 
  {
    return arg >= Low && arg <= High;
  }
}
До
private $low;
private $high;

function includes($arg) {
  return $arg >= $this->low && $arg <= $this->high;
}
Після
private $low;
private $high;

function includes($arg) {
  return $arg >= $this->getLow() && $arg <= $this->getHigh();
}
function getLow() {
  return $this->low;
}
function getHigh() {
  return $this->high;
}
До
class Range {
  private low: number
  private high: number;
  includes(arg: number): boolean {
    return arg >= low && arg <= high;
  }
}
Після
class Range {
  private low: number
  private high: number;
  includes(arg: number): boolean {
    return arg >= getLow() && arg <= getHigh();
  }
  getLow(): number {
    return low;
  }
  getHigh(): number {
    return high;
  }
}

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

Буває так, що вам перестає вистачати гнучкості з прямим доступом до приватного поля всередині класу. Ви хочете мати можливість ініціалізувати значення поля при першому запиті або робити якісь операції над новими значеннями поля в момент присвоєння, або робити все це різними способами в підкласах.

Переваги

  • Непрямий доступ до полів — це коли робота з полем відбувається через методи доступу (геттери і сеттери). Цей підхід відрізняється набагато більшою гнучкістю, ніж прямий доступ до полів.

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

    • По-друге, що ще важливіше, ви можете перевизначати геттери і сеттери в підкласах.

  • Ви можете взагалі не реалізовувати сеттер для поля. Значення поля задаватиметься тільки в конструкторі, роблячи це поле незмінним для всього періоду життя об’єкта.

Недоліки

  • Коли використовується прямий доступ до полів, код виглядає простіше і наочніше, хоча і втрачає в гнучкості.

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

  1. Створіть геттер (і, опціонально, сеттер) для поля. Вони мають бути захищеними (protected) або публічними (public).

  2. Знайдіть усі прямі звернення до поля і замініть їх викликами геттера і сеттера.