Проблема с длинными методами в том, что они теряют смысл метода.
Метод должен делать только одно.
Больше ничего. Не меньше.
И все же мы снова и снова нарушаем это правило.
Хорошее практическое правило?
- Если в вашем методе ›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/