Проблема с длинными методами в том, что они теряют смысл метода.

Метод должен делать только одно.

Больше ничего. Не меньше.

И все же мы снова и снова нарушаем это правило.

Хорошее практическое правило?

  • Если в вашем методе ›10 строк - вам нужно его реорганизовать.
  • Если вы считаете, что ваш код нуждается в нескольких комментариях - вам нужно его реорганизовать.

Методы

Извлекать

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

function checkIfPokemonHasLargeTail (pokemon) {
        var pokemonTailLength = pokemon.length - pokemon.bodyLength;
        var pokemonTailLengths = AllPokemon.map(function (p) {
            return p.length - p.bodyLength;
        });
        var totalPokemonTailLengths = pokemonTailLengths.reduce(function (p1, p2) {
            return p1 + p2;
        });
        var avergaePokemonTailLengths = totalPokemonTailLengths/ AllPokemon.length;
        return (pokemonTailLength > avergaePokemonTailLengths);
    }

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

  • Расчет длины хвоста
  • Расчет средней длины хвоста
  • Он проверяет, больше ли длина хвоста покемона, чем средняя длина хвоста покемона.

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

function getPokemonTailLength (pokemon) {
        return pokemon.length - pokemon.bodyLength;
    }
    function getAverageTailLength () {
        return AllPokemon.map(getPokemonTailLength).reduce(function (t1, t2) {
            return t1 + t2;
        })/ AllPokemon.length;
    }
    function checkIfPokemonHasLargeTail (pokemon) {
        return getPokemonTailLength(pokemon) > getAverageTailLength();
    }

Теперь, каковы преимущества этого

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

Теперь вы можете подумать, что у вас есть случаи, когда вы не можете применить этот метод извлечения.

Вот несколько методов решения этих проблем.

Заменить Temp запросом

function calculateNewPrice() {
        var basePrice = quantity * itemPrice;
        var newPrice = basePrice;
        if (basePrice > 1000) {
            newPrice = basePrice * 0.95;
        }
        else {
            newPrice = basePrice * 0.98;
        }
        newPrice = newPrice + Math.pow(newPrice,1/10);
        return newPrice;
    }

Здесь вам нужно извлечь используемую локальную переменную basePrice, прежде чем вы сможете применить extract. Любая локальная переменная является помехой - причины будут обсуждены в более позднем посте.

function calculateNewPrice() {
        return addShittyBusinessFactor(getDiscountePrice());
        
    }
    function addShittyBusinessFactor(newPrice) {
        return newPrice + Math.pow(newPrice,1/10);
    }
    function getDiscountePrice() {
        if (getBasePrice() > 1000) {
            return getBasePrice() * 0.95;
        }
        else {
            return getBasePrice() * 0.98;
        }
    }
    function getBasePrice() { // This is the replace temp with query portion
        return quantity * itemPrice;
    }

Ввести объект параметра

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

function getDatesOfEventInRange(startDate, endDate) {
        return AllEvents.filter(function (event) {
            return event.date > startDate && event.date < endDate
        });
    }

Это может служить препятствием для использования экстракта, и это можно решить, создав объект параметра только для этой функции.

function dateRange(startDate, endDate) {
        return {
            startDate: startDate,
            endDate: endDate,
            overlaps: function (date) {
                return date > startDate && date < endDate;
            }
        };
    }
    function getDatesOfEventInRange(dateRange) {
        return AllEvents.filter(function (event) {
            return dateRange.overlaps(event.date);
        });
    }

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

Если бы метод был длиннее, решение было бы более очевидным. Не стесняйтесь отправить мне хороший пример, и я добавлю ваше имя вместе с ним.

Сохранить объект целиком

Часто мы думаем о передаче аргументов как о частях объекта, а не о передаче всего объекта. Но в большинстве случаев отправка всего объекта может упростить использование метода извлечения.

var low = dayTempRange.low();
    var high = dayTempRange.high();
    var withinPlan = plan.withinRange(low, high);

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

var withinPlan = plan.withinRange(dayTempRange);

Если план поддерживает в качестве аргументов объекты типа dayTempRange, то проблема решена. Этот метод может потребоваться для быстрого использования метода извлечения.

Заменить метод объектом метода

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

Используемые локальные переменные могут стать локальными переменными объекта, и методы объекта могут их использовать.

Это потенциально может устранить множество сложностей, связанных со сложными методами.

Места, где можно использовать экстракт

Условные выражения и циклы - это части, в которых вы определенно можете извлечь код различными методами.

Для условных выражений

if (date.before(SUMMER_START)||date.after(SUMMER_END)) {
        // do something
    } else {
        // do something else
    }

Здесь вы можете извлечь условное с помощью -

if (isSummer(date)) {
        // do something
    } else {
        // do something else
    }

Для петель

var a = [];
    for (var i=0; i<10; i++) { 
        a.push(i);
    };

В

var a = range(10);

Больше моих статей читайте на https://www.oughttpot.tech/