Книга: Рефакторинг. Зачем?
Преобразование одной большой функции в две маленькие
Преобразование одной большой функции в две маленькие
Сейчас мы добрались до куда более сложной и куда менее однозначной темы. Дело в том, что человеческое восприятие так устроено, что анализировать сразу большой объём информации ему крайне сложно. Именно по этому, книги принято разбивать на главы, а сами главы на абзацы.
В программировании всё обстоит немного иначе и это может быть причиной путаницы. Тут текст разбит на функции (процедуры, методы, классы, сейчас это не так важно), а основное назначение функций — это возможность их повторного использования. То есть по сути, с их помощью суммарный объём кода уменьшается, они позволяют избежать многократного повторения одних и тех же фрагментов кода и тому подобное.
Использование функций как инструмента для улучшения читабельности кода, на мой взгляд, сильно недооценёно. Как показывает практика, небольшое усложнение кода ухудшает его восприятие значительно.
type
TRect = record
Left: Integer;
Right: Integer;
Top: Integer;
Bottom: Integer;
end;
function RectsLength(Rects: array of TRect): Integer;
var
I: Integer;
Width, Height: Integer;
begin
Result:= 0;
for I:= 0 to Length(Rects) — 1 do
begin
Width:= Rects[I].Right — Rects[I].Left;
Height:= Rects[I].Bottom — Rects[I].Top;
Result:= Result + 2 * Width + 2 * Height;
end;
end;
Выше приведён простой пример, который рассчитывает сумму периметров прямоугольников в массиве. Пока он не выглядит сильно сложным, но, предположим, что задача немного изменилась и нам сказали не учитывать прямоугольники площадью меньше некоего числа MinLength.
function RectsLength(Rects: array of TRect; MinLength: Integer): Integer;
var
I: Integer;
Width, Height, Len: Integer;
begin
Result:= 0;
for I:= 0 to Length(Rects) — 1 do
begin
Width:= Rects[I].Right — Rects[I].Left;
Height:= Rects[I].Bottom — Rects[I].Top;
Len:= 2 * Width + 2 * Height;
if Len >= MinLength then
Result:= Result + Len;
end;
end;
Не скажу, что намного сложнее, но взгляд спотыкается. А если бы мы сразу выделили функцию RectLenght, считающую площадь отдельного прямоугольника вышло бы несколько проще:
function RectLength(Rect: TRect): Integer;
var
Width, Height: Integer;
begin
Width:= Rect. Right — Rect. Left;
Height:= Rect. Bottom — Rect. Top;
Result:= 2 * Width + 2 * Height;
end;
function RectsLength(Rects: array of TRect; MinLength: Integer): Integer;
var
I: Integer;
Len: Integer;
begin
Result:= 0;
for I:= 0 to Length(Rects) — 1 do
begin
Len:= RectLength(Rects[I]);
if Len >= MinLength then
Result:= Result + Len;
end;
end;
И пусть вас не смущает, что в сумме кода стало немного больше. Мне ещё ни разу не приходилось жалеть о такого рода рефакторинге. То есть были, конечно, случаи, когда он был не оправдан и только путал… У каждого бывали ошибки. Но никогда проблемы не были связаны с увеличением суммарного объема кода. Иногда, даже если вы смогли разделить функцию на две функции того же размера (суммарное увеличение кода в два раза), но, при этом хорошо разделили их логически — это бывает оправдано.
Я не хочу сказать, что разбить большую функцию на две или несколько маленьких можно и нужно всегда. Принять решение об этом — задача, в ряде случаев, очень сложная. Поэтому, я хотел бы посвятить следующую главу признакам необъодимости такого рефакторинга.
- Введение
- Именование переменных и функций
- Стандартные имена функций и переменных
- Преобразование одной большой функции в две маленькие
- Признаки необходимости выделения функции
- Выделение функции в процессе написания
- Когда не следует выделять функцию
- Использование модулей
- Более сложные способы организации данных
- Объединение данных и кода
- Приватные члены класса
- Свойства
- Наследование
- Содержание книги
- Популярные страницы
- Преобразование XML в реляционную базу данных
- Аргументы функции в Python
- 3. Функции
- Новые функции API для работы с Blob и массивами
- Преобразование строки в целое: stoi( )
- Математические функции
- Размытые функции
- 7.3. Финансовые функции
- Глава 2. Что необходимо для беспроводной связи
- 4.3. Логические функции и таблицы истинности
- B1.7. Функции обработки ошибок
- 9.1.4.2. Функции-оболочки: execl() и др.