Також відомий як Duplicate Observed Data

Рефакторинг Дублювання видимих даних

Проблема

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

Рішення

Має сенс виділити дані предметної області в окремі класи і, таким чином, забезпечити зв'язок і синхронізацію між класом предметної області і GUI.
До
Duplicate Observed Data - Before
Після
Duplicate Observed Data - After

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

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

Переваги

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

  • Якщо потрібно буде додати новий вид інтерфейсу, вам треба буде створити нові класи представлення, при цьому код бізнес-логіки чіпати немає ніякої нужди (принцип відкритості/закритості).

  • Над бізнес-логікою і призначеними для користувача інтерфейсами тепер можуть працювати різні люди.

Коли не слід застосовувати

  • Цей рефакторинг, який в класичному виконанні здійснюється з введенням шаблону Спостерігач, практично не застосовується для веб-додатків, де всі класи перестворюються при кожному запиті до веб-сервера.

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

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

  1. Необхідно приховати прямий доступ до даних предметної області в _класі GUI _, для чого краще за всього використати «самоінкапсуляцію поля» (Self encapsulate field). Таким чином, ви створите геттери і сеттери до цих даних.

  2. У обробниках подій _класу GUI _ використайте сеттери для установки нових значень полів. Це дасть можливість передавати нові значення в пов'язаний об'єкт предметної області.

  3. Створіть клас предметної області і скопіюйте в нього необхідні поля з _класу GUI _. Для всіх цих полів створіть геттери і сеттери.

  4. Застосуйте патерн Спостерігач до цих двох класів:

  • В класі предметної області створіть масив для зберігання об'єктів спостерігачів (_об'єктів GUI _ ), а також методи їх реєстрації, видалення і сповіщення.
  • В _класі GUI _ створіть поле для зберігання посилання на об'єкт предметної області, а також метод update(), який реагуватиме на зміни в цьому об'єкті та буде оновлювати значення полів в _класі GUI _. Зверніть увагу, в методі оновлення значення повинні встановлюватися безпосередньо, щоб уникнути рекурсії.
  • У конструкторі _класу GUI _ створіть екземпляр класу предметної області і збережіть його в створеному полі. Зареєструйте об'єкт GUI як спостерігач в об'єкті предметної області.
  • У сеттерах полів класу предметної області викликайте метод сповіщення спостерігача (тобто метод оновлення в класі GUI), щоб передати нові значення в призначений для користувача інтерфейс.
  • Змініть сеттери полів _класу GUI _ так, щоб вони тепер встановлювали нові значення в об'єкті предметної області, причому безпосередньо. Будьте уважні, якщо значення встановлюватимуться через сеттер класу предметної області, це приведе до нескінченної рекурсії.

Замучились читати?

Збігайте за подушкою, в нас тут контенту приблизно на 7 годин читання.

Або спробуйте наш новий інтерактивний курс з рефакторингу. Він більш інформативний та набагато цікавіший за банальний тест.

Дізнатися більше...

Живий приклад

Перший раз у нас? Нічого страшного!

У нас тут все просто – цей інтерактивний приклад дуже схожий на відео (хоча й виглядає набагато крутіше).

  1. Натискаєте велику кнопку "Почати", а далі слідуєте усім підказкам.
  2. Ви можете перемотувати програвання, використовуючи стрілки зліва.
  3. Окрім того, ви можете подивитися різницю між стартовим та отриманим кодом, натиснувши кнопку ока ().
  4. Кнопка компіляції та тестування () дає змогу перевірити код на наявність помилок.