Відокремлення класу

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до навігації Перейти до пошуку

Відокрéмлення клáсу (англ. Extract class) — прийом рефакторингу, що полягає в розділенні класу та виділенні полів і методів, що підтримують окремий функціонал, у новостворений клас з метою полегшення роботи з даними.

Причини рефакторингу[ред. | ред. код]

У ході написання програми класи можуть отримати масу додаткових обов'язків.

Переваги здійснення відокремлення класу[ред. | ред. код]

  1. Функція такого рефакторингу — сприяння дотримання принципу єдиного обов'язку класу. В результаті код класів стає більш чистим і зрозумілим.
  2. Класи з єдиним обов'язком більш стійкі до змін. Наприклад, якщо є клас, який відповідає за 10 різних речей, і до нього потрібно внести певні зміни, то змінюючи один елемент є ризик пошкодити інші.

Недоліки[ред. | ред. код]

Якщо часто проводити такий рефакторинг, потрібно буде вдаватися до антирефакторингу — вбудовування класу.

Порядок рефакторингу[ред. | ред. код]

  1. Створити новий клас, який міститиме виділену функціональність.
  2. Створити зв'язок між старим і новим класом. Найкраще, якщо цей зв'язок буде одностороннім; при цьому другий клас можна буде без проблем використати повторно. З іншого боку, за необхідністю, завжди можна створити двосторонній зв'язок.
  3. Використати переміщення поля і переміщення методу для кожного поля і методу, які потрібно перенести в новий клас. Для методів слід розпочинати з приватних, таким чином знижуючи імовірність допустити масу помилок. Задля полегшення процесу виправлення помилок потрібно проводити тестування після кожного переміщення, аби не отримати багато помилок в кінці роботи.
  4. Після переміщення потрібно подивитись на отримані класи. Можливо, класи потрібно буде перейменувати, зважаючи на їх нові обов'язки. Також варто перевірити, чи можна позбавитися від двостороннього зв'язку між класами, якщо він з'явився.
  5. Важливим моментом є доступність класу ззовні: можна повністю сховати клас, зробивши приватним, і в той же час управляти його полями із старого класу, або зробити публічним, надавши клієнтові можливість безпосередньо міняти значення. Рішення залежить від того, наскільки безпечні для поведінки старого класу будуть несподівані прямі зміни значень в новому класі.

Приклад[ред. | ред. код]

Початковий клас
C#:

class Person
{
      public string getName() 
      {
          return _name;
      }
      public string GetTelephoneNumber() 
      {
          return ("(" + _officeAreaCode + ") " + _officeNumber);
      }
      string getOfficeAreaCode() 
      {
          return _officeAreaCode;
      }
      void GetOfficeAreaCode(string arg) 
      {
          _officeAreaCode = arg;
      }
      string getOfficeNumber() 
      {
          return _officeNumber;
      }
      void SetOfficeNumber(string arg) 
      {
          _officeNumber = arg;
      }
 
      private string _name;
      private string _officeAreaCode;
      private string _officeNumber;

У такому випадку власника телефонного номера можна виділити в окремий клас
C#:

class TelephoneNumber 
{
}

Потім потрібно зробити посилання з персони до телефонного номера
C#:

class Person
{
    ...
    private TelephoneNumber _officeTelephone = new TelephoneNumber();
    ...
}

Тепер потрібно виконати переміщення поля
C#:

class TelephoneNumber 
{
    string getAreaCode() 
    {
        return _areaCode;
    }
    void setAreaCode(string arg) 
    {
        _areaCode = arg;
    }
    private string _areaCode;
}

class Person
{
    public string GetTelephoneNumber() 
    {
        return ("(" + getOfficeAreaCode() + ") " + _officeNumber);
    }
    string getOfficeAreaCode() 
    {
        return _officeTelephone.getAreaCode();
    }
    void setOfficeAreaCode(string arg) 
    {
        _officeTelephone.setAreaCode(arg);
    }
}

Та переміщення методу
C#:

class Person
{
      public string getName() 
      {
          return _name;
      }
      public string getTelephoneNumber()
      {
          return _officeTelephone.getTelephoneNumber();
      }
      TelephoneNumber getOfficeTelephone() 
      {
          return _officeTelephone;
      }
 
      private String _name;
      private TelephoneNumber _officeTelephone = new TelephoneNumber();
}
    class TelephoneNumber
{
      public string GetTelephoneNumber()
      {
          return ("(" + _areaCode + ") " + _number);
      }
      string getAreaCode() 
      {
          return _areaCode;
      }
      void SetAreaCode(string arg) 
      {
          _areaCode = arg;
      }
      string getNumber() 
      {
          return _number;
      }
      void SetNumber(string arg) 
      {
          _number = arg;
      }
      private string _number;
      private string _areaCode;
}

Антирефакторинг[ред. | ред. код]

  • Вбудовування класу

Схожі рефакторинги[ред. | ред. код]

  • Витягання підкласу
  • Заміна простого поля об'єктом

Бореться з запахом[ред. | ред. код]

Посилання[ред. | ред. код]