Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Технологии программирования. Учебное пособие

.pdf
Скачиваний:
1
Добавлен:
15.08.2026
Размер:
1 Мб
Скачать

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

Высота дерева наследования (Depth of Inheritance Tree) –

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

Количество детей (Number Of Children) – значением этой метрики будет количество непосредственных классов-наследников рассматриваемого класса. С увеличением количества наследников возрастает многократность использования методов и свойств классов, что является хорошей характеристикой, но при этом возникает риск неправильного использования некоторых классовнаследников. Поэтому значение данной метрики должно быть разумно низким.

Сцепление между классами объектов (Coupling Between Object Classes) – рассчитывается количество классов, с которыми соединен рассматриваемый класс. Соединение образуется в результате вызова рассматриваемым классом метода или свойства другого класса. Низкая величина сцепления для класса более предпочтительна, так как большое количество сцеплений влияет на чувствительность всего проекта к любым изменениям: изменение в одном модуле может вести к необходимости изменений во многих других модулях,

11

все необходимые изменения трудно отследить. Это влечет за собой увеличение количества ошибок при тестировании.

Отклик для класса (Response For a Class) – при расчете показателя для класса используется количество собственных методов класса, а также количество методов, которые могут быть вызваны из рассматриваемого класса. Большое значение этой метрики свидетельствует о высокой сложности класса, что негативно сказывается на процессе тестирования и отладки.

Недостаток связности в методах (Lack of Cohesion in Methods) – значение метрики показывает, насколько в классе количество пар методов, не связанных по свойствам класса, преобладает над количеством пар методов, связанных по свойствам класса. Высокая связность класса по методам является хорошей характеристикой, так как это содействует инкапсуляции. Следовательно, высокое значение этой метрики, напротив, говорит о низкой связности.

Пример расчета метрик Чидамбера и Кемерера для диаграммы UML, изображенной на рисунке 1.4, представлен в таблице 1.2.

Рисунок 1.4. Диаграмма UML для расчета метрик Чидамбера и Кемерера

12

Таблица 1.2

Пример расчета метрик

Имя

Взвешенные

Высота

Количество

Сцепление

Отклик

Недостаток

класса

методы на

дерева

детей

между

для

связности

 

класс

наследо-

 

классами

класса

в методах

 

 

вания

 

объектов

 

 

 

 

 

 

 

 

 

Class А

4

0

3

1

5

4

 

 

 

 

 

 

 

Class В

1

1

0

0

1

0

 

 

 

 

 

 

 

Class С

1

1

0

0

1

0

 

 

 

 

 

 

 

Class D

2

1

0

0

2

0

 

 

 

 

 

 

 

Class E

1

0

0

0

1

0

 

 

 

 

 

 

 

Прокомментируем результаты расчета. Класс Class А имеет три метода (a1(), а2(), аЗ()), трех детей (Class В, Class С, Class D) и

является корневым классом. Поэтому метрики «взвешенные методы на класс», «количество детей» и «высота дерева наследования» имеют, соответственно, значения 3, 3 и 0. Метрика «сцепление между классами объектов» для класса Class А равна 1, так как он использует один метод из другого класса (метод е() из класса Class E, он вызывается из метода сreateE()). Метрика «отклик для класса» для класса Class А равна 5, так как в ответ на прибытие в этот класс сообщений возможно выполнение пяти методов (четыре объявлены в этом классе, а пятый метод е() вызывается из сreateE()). Рассчитаем метрику «недостаток связности в методах», поскольку в классе А четыре метода, возможны шесть пар: a1()&a2(), a1()&a3(), a1()&сreateE(), a2()&a3(), a2()&сreateE(), a3&сreateE(). Методы a2()

и a3() связаны по переменной pa1(), остальные не имеют общих переменных. Таким образом, количество не связанных пар равно пяти, а связанных один. Следовательно, «недостаток связности в методах» равен четырем.

13

Вопросы к главе:

1.Охарактеризуйте класс программ, для которых предложенные метрики являются наиболее эффективными.

2.Приведите недостатки предложенных метрик.

3.Какие свойства объектно-ориентированных программ не учитывают метрики Чидамбера и Кемерера?

4.Что означают высокие значения метрики «недостаток связности в методах»?

14

ГЛАВА 2. РЕФАКТОРИНГ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ

Рефакторинг (англ. refactoring), или перепроектирование кода, переработка кода, равносильное преобразование алгоритмов ‒ процесс изменения внутренней структуры программы, не затрагивающий ее внешнего поведения и имеющий целью облегчить понимание ее работы.

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

Чтобы избегать разрушения программного обеспечения (ПО) и поддерживать целостность архитектуры, необходимо часто проводить рефакторинг, чтобы быть уверенным, что код остается чистым и лаконичным и с минимальными зависимостями между модулями. Качество кода и метрики проектирования предлагают объективные рекомендации при определении участков кода в приложении, которые являются первоочередными кандидатами для рефакторинга. Метрики покрытия позволяют выполнять работы по рефакторингу.

Проблемы в коде, требующие рефакторинга:

-дублирование кода;

-длинный метод;

-большой класс;

-длинный список параметров;

-«жадные» функции ‒ это метод, который чрезмерно обращается

кданным другого объекта;

-избыточные временные переменные;

15

-классы данных;

-не сгруппированные данные. Методы рефакторинга:

-Инкапсуляция поля (Encapsulate Field);

-Выделение класса (Extract Class);

-Выделение интерфейса (Extract Interface);

-Выделение локальной переменной (Extract Local Variable);

-Выделение метода (Extract Method);

-Генерализация типа (Generalize Type);

-Встраивание (Inline);

-Введение фабрики (Introduce Factory);

-Введение параметра (Introduce Parameter);

-Подъем поля/метода (Pull Up);

-Спуск поля/метода (Push Down);

-Замена условного оператора полиморфизмом (Replacing a conditional operator with a polymorphism).

Всистеме Visual Studio существуют механизмы для проведения рефакторинга. Существует много способов вызвать инструменты для рефакторинга, включая контекстное меню, которое открывается после щелчка правой кнопкой мыши, интеллектуальные дескрипторы и меню Refactor.

На рисунке 2.1 показано контекстное меню Refactor, предназначенное для разработчиков, работающих на языке программирования C#. Полный список действий по рефакторингу, доступных для разработчиков C# в системе Visual Studio, включает операции «Переименовать», «Извлечь метод», «Инкапсулировать

поле», «Извлечь интерфейс», «Удалить параметры» и

«Упорядочить параметры». Можно также использовать операции

«GenerateMethodStub» и «OrganizeUsings», которые с некоторой натяжкой также можно отнести к рефакторингу.

16

Рисунок 2.1. Контекстное меню «Выполнить рефакториг»

Рассмотрим примеры использования встроенной поддержки рефакторинга в языке C#.

Чтобы начать рефакторинг длинного метода, лучше всего разбить его на несколько небольших частей. Для этого необходимо выделить область кода, которую необходимо удалить из исходного метода, и выбрать операцию «Извлечь метод». В языке C# это приведет к появлению приглашения ввести имя нового метода, как показано на рисунке 2.2. Если в удаляемом блоке кода есть переменные, которые использовались ранее, они автоматически становятся переменными в сигнатуре нового метода. После подтверждения имени нового метода его код вставляется сразу после исходного метода. Удаленный блок метода заменяется вызовом нового метода.

17

Рисунок 2.2. Окно «Извлечь метод»

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

public string Statement()

{

double totalAmount = 0;

int frequentRenterPoints = 0;

string result = string.Format("Учет аренды для {0}:", name);

foreach (Rental rental in rentals)

{

double thisAmount = 0;

// Выделите текст с этого места switch (rental.Movie.PriceCode)

{

case Movie.Regular: thisAmount += 2;

if (rental.DaysRented > 2)

thisAmount += (rental.DaysRented - 2) * 1.5; break;

case Movie.New_Release: thisAmount += rental.DaysRented * 3;

break;

18

case Movie.Childrens: if (rental.DaysRented > 3)

thisAmount += (rental.DaysRented - 3) * 1.5; break;

}

// досюда, и вызовите команду «Извлечь метод» /* ... Продолжение длинного метода ... */

frequentRenterPoints++;

if ((rental.Movie.PriceCode == Movie.New_Release) && (rental.DaysRented > 1))

frequentRenterPoints++;

result += "\t" + rental.Movie.Title + "\t" + thisAmount; totalAmount += thisAmount;

}

result += "Сумма составляет" + totalAmount + "\n";

result += "Вы заработали" + frequentRenterPoints + "очков за активность"; return result;

}

public string Statement()

{

double totalAmount = 0;

int frequentRenterPoints = 0;

string result = string.Format("Учет аренды для {0}:", name);

foreach (Rental rental in rentals)

{

double thisAmount = 0;

// Выделите текст с этого места

thisAmount = NewMethod(rental, thisAmount); // вызов извлеченного

метода

// досюда, и вызовите команду «Извлечь метод» /* ... Продолжение длинного метода ... */ frequentRenterPoints++;

19

if ((rental.Movie.PriceCode == Movie.New_Release) && (rental.DaysRented > 1))

frequentRenterPoints++;

result += "\t" + rental.Movie.Title + "\t" + thisAmount; totalAmount += thisAmount;

}

result += "Сумма составляет" + totalAmount + "\n";

result += "Вы заработали" + frequentRenterPoints + "очков за активность"; return result;

}

В результате получим новый метод:

private static double NewMethod(Rental rental, double thisAmount)

{

switch (rental.Movie.PriceCode)

{

case Movie.Regular: thisAmount += 2;

if (rental.DaysRented > 2)

thisAmount += (rental.DaysRented - 2) * 1.5; break;

case Movie.New_Release:

thisAmount += rental.DaysRented * 3; break;

case Movie.Childrens:

if (rental.DaysRented > 3)

thisAmount += (rental.DaysRented - 3) * 1.5; break;

}

return thisAmount;

}

При рефакторинге часто требуется инкапсулировать в существующий класс некое свойство. Для этого используется операция «Инкапсулировать поле». Для выполнения

20

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]