14.02.2019

Самокапсулювання

Original: https://martinfowler.com/bliki/SelfEncapsulation.html

Мартін Фаулер

9 березня 2017

 

Капсулювання даних є центральним принципом об’єктно-орієнтованого стилю. Це говорить про те, що поля об’єкта не повинні піддаватися відкрито, замість того, щоб весь доступ з-за меж об’єкта здійснювався за допомогою методів доступу (геттери та сеттери). Є мови, які дозволяють відкрити доступні поля, але ми зазвичай попереджаємо програмістів не робити цього. Самокапсулювання йде далі, вказуючи на те, що весь внутрішній доступ до поля даних також повинен пройти через методи доступу. Тільки методи доступу повинні торкатися самого значення даних. Якщо поле даних не експоновано зовні, це означатиме додавання додаткових приватних додатків.

Ось приклад розумно інкапсульованого класу java

клас Charge…

  private int units;
  private double rate;

  public Charge(int units, double rate) {
    this.units = units;
    this.rate = rate;
  }
  public int getUnits() { return units; }
  public Money getAmount() { return Money.usd(units * rate); }

Обидва поля є незмінними. Поле блоків піддається клієнтам класу через геттер, але поле швидкості використовується лише внутрішньо, тому не потребує геттера.

Ось версія з використанням самокапсулювання.

клас ChargeSE…

  private int units;
  private double rate;

  public ChargeSE(int units, double rate) {
    this.units = units;
    this.rate = rate;
  }
  public int getUnits()    { return units; }
  private double getRate() { return rate; }
  public Money getAmount() { return Money.usd(getUnits() * getRate()); }

Самокапсулювання означає, щоgetAmountпотребує доступу до обох полів через геттерів. Це також означає, що я повинен додати геттера дляrate швидкості, яку я повинен зробити приватною.

Капсулювання змінюваних даних, як правило, є хорошою ідеєю. Функції поновлення можуть містити код для виконання перевірок і, як наслідок логіки. Обмежуючи доступ через функцію, ми можемо підтримати UniformAccessPrinciple, що дозволяє нам приховувати, які дані обчислюються і зберігаються. Ці аксессор дозволяють змінювати структуру даних, зберігаючи при цьому один і той же відкритий інтерфейс. Різні мови розрізняються в деталях, що «зовні» для об’єкта різними видами AccessModifier, але більшість середовищ підтримують інкапсуляцію даних в деякій мірі.

Я зіткнувся з кількома організаціями, які мандатували самостійну інкапсуляцію, і чи варто було її використовувати чи ні, це було регулярною темою дебатів з 90-х років. Її захисники сказали, що інкапсуляція була такою перевагою, що ви хотіли включити її до внутрішнього доступу. Критики стверджували, що це була непотрібна церемонія, що призводила до непотрібного коду, який затушовував те, що відбувалося.

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

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

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

Подальше читання

Кент Бек обговорює ці компромісні під назвами прямий доступу і непрямий доступ в обох Зразки реалізації і Smalltalk Best Practice Patterns

Подяка

Ян Картрайт, Маттео Ваккарі та Філіп Дулдіг прокоментували проекти цього поста

 

 

About The Author

admin

Comments are closed.