Autumn SALE

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

Также известен как: 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. Найдите все прямые обращения к полю и замените их вызовами геттера и сеттера.