Глянь мій новий курс по Git! Привіт! Глянь мій новий курс по Git! Привіт! Глянь мій новий курс по Git на GitByBit.com! Привіт! Хочеш класно освіжити Git? Глянь мій новий курс на GitByBit.com!

Заміна вкладених умовних операторів граничним оператором

Також відомий як: Replace Nested Conditional with Guard Clauses

Проблема

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

Рішення

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

До
public double getPayAmount() {
  double result;
  if (isDead){
    result = deadAmount();
  }
  else {
    if (isSeparated){
      result = separatedAmount();
    }
    else {
      if (isRetired){
        result = retiredAmount();
      }
      else{
        result = normalPayAmount();
      }
    }
  }
  return result;
}
Після
public double getPayAmount() {
  if (isDead){
    return deadAmount();
  }
  if (isSeparated){
    return separatedAmount();
  }
  if (isRetired){
    return retiredAmount();
  }
  return normalPayAmount();
}
До
public double GetPayAmount()
{
  double result;
  
  if (isDead)
  {
    result = DeadAmount();
  }
  else 
  {
    if (isSeparated)
    {
      result = SeparatedAmount();
    }
    else 
    {
      if (isRetired)
      {
        result = RetiredAmount();
      }
      else
      {
        result = NormalPayAmount();
      }
    }
  }
  
  return result;
}
Після
public double GetPayAmount() 
{
  if (isDead)
  {
    return DeadAmount();
  }
  if (isSeparated)
  {
    return SeparatedAmount();
  }
  if (isRetired)
  {
    return RetiredAmount();
  }
  return NormalPayAmount();
}
До
function getPayAmount() {
  if ($this->isDead) {
    $result = $this->deadAmount();
  } else {
    if ($this->isSeparated) {
      $result = $this->separatedAmount();
    } else {
      if ($this->isRetired) {
        $result = $this->retiredAmount();
      } else {
        $result = $this->normalPayAmount();
      }
    }
  }
  return $result;
}
Після
function getPayAmount() {
  if ($this->isDead) {
    return $this->deadAmount();
  }
  if ($this->isSeparated) {
    return $this->separatedAmount();
  }
  if ($this->isRetired) {
    return $this->retiredAmount();
  }
  return $this->normalPayAmount();
}
До
def getPayAmount(self):
    if self.isDead:
        result = deadAmount()
    else:
        if self.isSeparated:
            result = separatedAmount()
        else:
            if self.isRetired:
                result = retiredAmount()
            else:
                result = normalPayAmount()
    return result
Після
def getPayAmount(self):
    if self.isDead:
        return deadAmount()
    if self.isSeparated:
        return separatedAmount()
    if self.isRetired:
        return retiredAmount()
    return normalPayAmount()
До
getPayAmount(): number {
  let result: number;
  if (isDead){
    result = deadAmount();
  }
  else {
    if (isSeparated){
      result = separatedAmount();
    }
    else {
      if (isRetired){
        result = retiredAmount();
      }
      else{
        result = normalPayAmount();
      }
    }
  }
  return result;
}
Після
getPayAmount(): number {
  if (isDead){
    return deadAmount();
  }
  if (isSeparated){
    return separatedAmount();
  }
  if (isRetired){
    return retiredAmount();
  }
  return normalPayAmount();
}

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

«Умовний оператор з пекла» досить просто відрізнити. Відступи кожного з рівнів вкладеності формують в нім виразну стрілку, що вказує направо:

if () {
    if () {
        do {
            if () {
                if () {
                    if () {
                        ...
                    }
                }
                ...
            }
            ...
        }
        while ();
        ...
    }
    else {
        ...
    }
}

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

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

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

Намагайтеся позбутися від «побічних ефектів» в умовах операторів. Розділення запиту і модифікатора може в цьому допомогти. Таке рішення знадобиться для подальших перестановок умов.

  1. Виділіть граничні умови, які призводять до виклику виключення або негайного повернення значення з методу. Перемістіть ці умови в початок методу.

  2. Після того, як з перенесеннями покінчено, і усі тести стали проходити, перевірте, чи можна використати ооб’єднання умовних операторів для граничних умовних операторів, що ведуть до однакових виключень або значень, які повертаються.