Рефакторинг: введение объясняющих переменных

Иногда в исходном коде выражения бывают настолько сложными, что если даже и мы их написали, то по прошествии какого-то времени не можем понять, что мы имели в виду в том или ином участке кода.

Например, рассмотрим следующее выражение (правда, оно не настолько сложное, но выражения посложнее я покажу далее):

if ((strpos(strtoupper($platform), "MAC") !== false) &&
    (strpos(strtoupper($browser),  "IE")  !== false) &&
     wasInitialized() && $resize > 0 ) {
        // что-то делаем ...
}

Чтобы нам легче было понять логическое выражение в условии, попробуем упростить его с помощью нашего сегодняшнего приема:

$isMacOs     = strpos(strtoupper($platform), "MAC") !== false;
$isIEBrowser = strpos(strtoupper($browser),  "IE")  !== false;
$wasResized  = $resize > 0;
if ($isMacOs && $isIEBrowser && wasInitialized() && $wasResized) {
    // что-то делаем ...
}

Выражение могут быть очень сложными для понимания и чтения. В таких случаях введение локальных переменных может существенно помочь разбить сложное и длинное выражение на ряд более простых. Только тут надо учитывать, что имена переменных должны быть понятны читателю кода, т.е. они должны отражать суть того, что делает выражение, результат которого сохраняется в переменной.

Иногда бывает трудно применить прием группировки кода в отдельную функцию, о котором мы говорили ранее. И наш сегодняшний прием немного может облегчить нам жизнь в этом случае.

Рассмотрим теперь пример посложнее:

function price() {
    // цена = базовая_цена - скидка + стоимость_доставки
    return $this->_quantity * $this->_itemPrice -
        max(0, $this->_quantity - 500) * $this->_itemPrice * 0.05 +
        min($this->_quantity * $this->_itemPrice * 0.1, 100.0);
}

Во-первых, в примере базовая цена вычисляется как цена одной единицы, умноженная на количество товара. Мы можем с легкостью выделить это в отдельную переменную:

function price() {
    // цена = базовая_цена - скидка + стоимость_доставки
    $basePrice = $this->_quantity * $this->_itemPrice;
    return $basePrice  -
        max(0, $this->_quantity - 500) * $this->_itemPrice * 0.05 +
        min($basePrice * 0.1, 100.0);
}

Во-вторых, мы можем выделить вычисление скидки в отдельную переменную:

function price() {
    // цена = базовая_цена - скидка + стоимость_доставки
    $basePrice   = $this->_quantity * $this->_itemPrice;
    $qtyDiscount = max(0, $this->_quantity - 500) * $this->_itemPrice * 0.05;
    return $basePrice - $qtyDiscount + min($basePrice * 0.1, 100.0);
}

В конце концов, я могу вынести определение стоимости доставки в третью переменную. При этом я могу удалить комментарий, т.к. он для понимания кода уже не нужен:

function price() {
    $basePrice   = $this->_quantity * $this->_itemPrice;
    $qtyDiscount = max(0, $this->_quantity - 500) * $this->_itemPrice * 0.05;
    $shipping    = min($basePrice * 0.1, 100.0);
    return $basePrice - $qtyDiscount + $shipping;
}

Но здесь мы могли бы вполне использовать прием группировки кода в отдельную функцию:

function price() {
    return basePrice() - qtyDiscount() + shipping();
}
function quantityDiscount() {
    return max(0, $this->_quantity - 500) * $this->_itemPrice * 0.05;
}
function shipping() {
    return min($this->basePrice() * 0.1, 100.0);
}
function basePrice() {
    return $this->_quantity * $this->_itemPrice;
}

Я предпочел бы использовать именно группировку кода в отдельную функцию, т.к. в этом случае выделенные методы quantityDiscount, shipping и basePrice доступны любой части объекта, в котором мы их используем. Но если у нас есть довольно сложное выражение, которое не позволит нам просто так применить прием группировки, мы вынуждены будем применить наш сегодняшний прием введения объясняющих переменных.





Читайте также:



3 Ответов на “Рефакторинг: введение объясняющих переменных”

  1. Игорь

    Хороший прием для качественного кода, но делать руппировку кода в отдельную функцию надо только тогда когда код встречается более двух раз, а если нет то переменные самый раз.

  2. Нашёл ошибку, по крайне мере у меня не воспринимает браузер пока не исправил: #
    # function quantityDiscount() {
    # return max(0, $this->_quantity - 500) * $this->_itemPrice * 0.06;
    Кто нить уже пробовал код?

  3. novice

    2 iwan: не воспринимает скорее всего не браузер, а php-интерпретатор ) Тут конечно будет ошибка, если держать этот код не в классе, в котором есть поля _quantity и _itemPrice. А вообще этот код просто для примера приведен, его даже пробовать не стоит :) Достаточно понять смысл приема.


© Copyright. . I-Novice. All Rights Reserved. Terms | Site Map