Файл: Руководство по стилю программирования и конструированию по.pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 30.11.2023
Просмотров: 856
Скачиваний: 2
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
СОДЕРЖАНИЕ
ГЛАВА 24 Рефакторинг
563
вильная абстракция взаимодействия Класса A с Классом B. Если за вызов C дол- жен отвечать B, внесите нужные изменения.
Удаление посредника Если Класс A вызывает Класс B, а Класс B вызывает Класс
C, подумайте, не лучше ли вызывать C непосредственно из A. Целесообразность делегирования полномочий Классу B зависит от того, улучшит ли это целостность его интерфейса или ухудшит.
Замена наследования на делегирование Если из одного класса нужно исполь- зовать другой класс, но вы хотите получить больший контроль над интерфейсом второго класса, сделайте суперкласс полем бывшего подкласса и создайте для доступа к нему набор открытых методов, формирующих связную абстракцию.
Замена делегирования на наследование Если класс предоставляет доступ ко всем открытым методам класса-делегата (класса-члена), выполните наследование от класса-делегата, а не просто используйте его.
Создание внешнего метода Если в класс нужно включить дополнительный ме- тод, но изменять класс нельзя, вы можете создать нужный метод в клиентском классе.
Создание класса-расширения Если в класс нужно включить несколько допол- нительных методов, но изменять класс нельзя, вы можете создать новый класс,
объединяющий функциональность неизменяемого класса с дополнительной функ- циональностью. Для этого вы можете или выполнить наследование от исходного класса и добавить новые методы в подклассы, или заключить класс в оболочку,
предоставив доступ к нужным методам.
Инкапсуляция открытой переменной-члена Если данные-члены открыты,
сделайте их закрытыми и реализуйте доступ к ним при помощи методов.
Удаление методов установки значений неизменяемых полей Если поле предполагается устанавливать во время создания объекта и не изменять впослед- ствии, инициализируйте поле в конструкторе объекта и не создавайте вводящий в заблуждение метод
Set().
Сокрытие методов, которые не следует вызывать извне класса Если без метода интерфейс класса будет более согласованным, скройте метод.
Инкапсуляция неиспользуемых методов Если обычно вы используете толь- ко часть интерфейса класса, создайте новый интерфейс, предоставляющий до- ступ только к необходимым методам. Убедитесь в том, что новый интерфейс фор- мирует согласованную абстракцию.
Объединение суперкласса и подкласса, имеющих очень похожую реали-
зацию Если степень специализации подкласса невысока, объедините его с су- перклассом.
Рефакторинг на уровне системы
Создание эталонного источника данных, которые вы не можете конт-
ролировать Иногда какие-то данные трудно согласованно использовать из дру- гих объектов, которым нужны эти данные. В качестве примера можно привести данные элемента управления с GUI-интерфейсом. В этом случае вы можете создать
564
ЧАСТЬ V Усовершенствование кода класс, воспроизводящий данные элемента управления, и рассматривать этот класс как эталонный источник данных и для элемента управления, и для другого кода.
Изменение однонаправленной связи между классами на двунаправленную
Если два класса должны использовать возможности друг друга, но только один класс знает о другом классе, измените классы так, чтобы они оба знали друг о друге.
Изменение двунаправленной связи между классами на однонаправленную
Если два класса известны друг другу, но на самом деле только один класс должен знать о другом, измените характер связи между классами.
Предоставление фабричного метода вместо простого конструктора Ис- пользуйте фабричный метод, если вам нужно создавать объекты на основе кода типа или если вы хотите работать с объектами-ссылками, а не объектами-значениями.
Замена кодов ошибок на исключения или наоборот Убедитесь, что вы ис- пользуете стандартный подход к обработке ошибок, основанный на той или иной стратегии.
Контрольный список: виды рефакторинга
Рефакторинг на уровне данных
Замена магического числа на именованную константу.
Присвоение переменной более ясного или информативного имени.
Встраивание выражения в код.
Замена выражения на вызов метода.
Введение промежуточной переменной.
Преобразование многоцелевой переменной в несколько одноцелевых пере- менных.
Использование локальной переменной вместо параметра.
Преобразование элементарного типа данных в класс.
Преобразование набора кодов в класс или перечисление.
Преобразование набора кодов в класс, имеющий производные классы.
Преобразование массива в класс.
Инкапсуляция набора.
Замена традиционной записи на класс данных.
Рефакторинг на уровне отдельных операторов
Декомпозиция логического выражения.
Вынесение сложного логического выражения в грамотно названную булеву функцию.
Консолидация фрагментов, повторяющихся в разных частях условного опе- ратора.
Использование оператора break / return вместо управляющей переменной цикла.
Возврат из метода сразу после получения ответа вместо установки возвра- щаемого значения внутри вложенных операторов if-then-else.
Замена условных операторов (особенно многочисленных блоков case) на вызов полиморфного метода.
Создание и использование «пустых» объектов вместо проверки того, равно ли значение null.
http://cc2e.com/2450
1 ... 65 66 67 68 69 70 71 72 ... 104
ГЛАВА 24 Рефакторинг
565
Рефакторинг на уровне отдельных методов
Извлечение метода из другого метода.
Встраивание кода метода.
Преобразование объемного метода в класс.
Замена сложного алгоритма на простой.
Добавление параметра.
Удаление параметра.
Отделение операций запроса данных от операций изменения данных.
Объединение похожих методов при помощи их параметризации.
Разделение метода, поведение которого зависит от полученных параметров.
Передача в метод целого объекта вместо отдельных полей.
Передача в метод отдельных полей вместо целого объекта.
Инкапсуляция нисходящего приведения типов.
Рефакторинг реализации классов
Замена объектов-значений на объекты-ссылки.
Замена объектов-ссылок на объекты-значения.
Замена виртуальных методов на инициализацию данных.
Изменение положения методов-членов или данных-членов в иерархии на- следования.
Перемещение специализированного кода в подкласс.
Объединение похожего кода и его перемещение в суперкласс.
Рефакторинг интерфейсов классов
Перемещение метода в другой класс.
Разделение одного класса на несколько.
Удаление класса.
Сокрытие делегата.
Удаление посредника.
Замена наследования на делегирование.
Замена делегирования на наследование.
Создание внешнего метода.
Создание класса-расширения.
Инкапсуляция открытой переменной-члена.
Удаление методов установки значений неизменяемых полей.
Сокрытие методов, которые не следует вызывать извне класса.
Инкапсуляция неиспользуемых методов.
Объединение суперкласса и подкласса, имеющих очень похожую реализацию.
Рефакторинг на уровне системы
Создание эталонного источника данных, которые вы не можете контроли- ровать.
Изменение однонаправленной связи между классами на двунаправленную.
Изменение двунаправленной связи между классами на однонаправленную.
Предоставление фабричного метода вместо простого конструктора.
Замена кодов ошибок на исключения или наоборот.
566
ЧАСТЬ V Усовершенствование кода
24.4. Безопасный рефакторинг
Рефакторинг — эффективный способ повышения качества кода. Но, как и все эффективные инструменты, при невер- ном использовании он может причинить вред. Несколько простых советов помогут предотвратить неверное приме- нение рефакторинга.
Сохраняйте первоначальный код Перед началом рефак- торинга убедитесь, что вы сможете вернуться к коду, с ко- торого начинаете. Сохраните код в системе управления вер- сиями или скопируйте корректные файлы в резервный ка- талог.
Стремитесь ограничить объем отдельных видов рефакторинга Некото- рые виды рефакторинга масштабнее других, к тому же не всегда можно точно ска- зать, что именно составляет «один вид рефакторинга». Чтобы четко представлять все следствия вносимых изменений, не раздувайте виды рефакторинга. Примеры соблюдения этого принципа см. в книге «Refactoring» (Fowler, 1999).
Выполняйте отдельные виды рефакторинга по одному за раз Некоторые виды рефакторинга сложнее других. За исключением самых простых случаев выполняйте все виды рефакторинга по одному за раз, компилируя и тестируя программу перед следующим видом рефакторинга.
Составьте список действий, которые вы собираетесь предпринять Ес- тественным расширением Процесса Программирования с Псевдокодом является составление списка видов рефакторинга, которые приведут вас из точки А в точ- ку Б. Составление такого списка поможет поддерживать каждое изменение в со- ответствующем контексте.
Составьте и поддерживайте список видов рефакторинга, которые сле-
дует выполнить позже Выполняя один вид рефакторинга, вы можете счесть необходимым еще один вид. Взявшись за него, вы можете обнаружить в коде не- достатки, призывающие к третьему виду. Если изменение не требуется сию мину- ту, включите его в список изменений, которые следовало бы внести в программу когда-то, но не обязательно вносить прямо сейчас.
Часто создавайте контрольные точки Иногда рефакторинг внезапно ухо- дит в сторону, поэтому вам следует не только сохранять первоначальный код, но и создавать контрольные точки на разных этапах рефакторинга, чтобы можно было вернуться к работоспособной программе, если рефакторинг заведет вас в тупик.
Используйте предупреждения компилятора Компилятор часто не замеча- ет небольших ошибок. Задав компилятору самый строгий уровень диагностики,
вы сможете исправлять многие ошибки почти сразу после их внесения.
Выполняйте регрессивное тестирование Дополните обзоры измененного кода регрессивным тестированием. Конечно, это зависит от наличия хорошего набора тестов (см. главу 22).
Вмешательство в рабочую сис- тему больше похоже на вскры- тие головного мозга и замену нерва, чем на замену проклад- ки в кране. Облегчилось ли бы сопровождение программ, если б оно называлось «нейрохирур- гией ПО»?
Джеральд Вайнберг
(Gerald Weinberg)
ГЛАВА 24 Рефакторинг
567
Создавайте дополнительные тесты Не ограничивайтесь регрессивным тес- тированием программы с использованием старых тестов — создавайте новые блочные тесты для проверки нового кода. Тесты, устаревшие в результате рефак- торинга, удаляйте.
Выполняйте обзоры изменений Если обзоры важны при первоначальном написании кода, то при последующих изме- нениях их важность лишь повышается. Эд Йордон сообщает,
что первая попытка внесения изменения в код более чем в половине случаев оказы- вается ошибочной (Yourdon, 1986b). Интересно, что, если программисты имеют дело не с несколькими строками кода, а с более объемным фрагментом, вероятность вне- сения корректного изменения более высока (рис. 24-1). Точнее говоря, по мере уве- личения числа изменяемых строк с одной до пяти вероятность внесения непра- вильного изменения повышается, а после этого снижается.
Рис. 24-1. Небольшие изменения чаще оказываются ошибочными,
чем более крупные (Weinberg, 1983)
Программисты относятся к небольшим изменениям легкомысленно. Они не ана- лизируют их, не просят коллег выполнить их обзор, а иногда даже не запускают программу, чтобы проверить, что исправление корректно.
Мораль проста: рассматривайте простые изменения так, как если бы они были сложными. В одной организации, в которой были введены обзоры изменений одной строки кода, было обнаружено, что доля ошибочных изменений снизилась с 55% до 2% (Freedman and Weinberg, 1982). В другой орга- низации, работающей в сфере телекоммуникаций, введение обзоров изменений позволило повысить их корректность с 86% до 99,6% (Perrott, 2004).
Изменяйте подход в зависимости от рискованности рефакторинга Не- которые виды рефакторинга сопряжены с более высоким риском, чем другие. Так,
«замена магического числа на именованную константу» относительно безопасна.
Виды рефакторинга, предполагающие изменение интерфейса класса или метода,
схемы БД или булевых тестов, обычно более рискованны. Если рефакторинг не- сложен, вы можете оптимизировать процесс рефакторинга, выполняя более од- ного вида за раз и ограничиваясь регрессивным тестированием кода без его офи- циального обзора.
Перекрестная ссылка Об обзо- рах см. главу 21.
568
ЧАСТЬ V Усовершенствование кода
В случае более рискованных видов рефакторинга будьте более осторожны. Вы- полняйте их по одному за раз. Попросите кого-то провести обзор изменения или выполните рефакторинг в паре, дополнив этим обычную проверку кода средствами компилятора и блочное тестирование.
Плохие причины выполнения рефакторинга
Несмотря на всю свою эффективность, рефакторинг — не панацея и допускает несколько специфических видов злоупотребления.
Не рассматривайте рефакторинг как оправдание на-
писания плохого кода с намерением исправить его
позднее Самой большой проблемой с рефакторингом яв- ляется его неверное применение. Иногда программисты говорят, что они выполняют рефакторинг, хотя на самом деле они просто пробуют что попало в надежде хоть как- то привести код в работоспособное состояние. Рефакторинг — это
изменение
работоспособного кода, не влияющее на поведение программы. Программисты,
которые возятся с плохим кодом, не выполняют рефакторинг — они занимаются хакерством.
Не рассматривайте рефакторинг как способ, позво-
ляющий избежать переписывания кода Иногда код невозможно улучшить небольшими изменениями — его нуж- но выбросить и переписать с нуля. Если вы выполняете круп- номасштабный рефакторинг, спросите себя, не следует ли вместо этого перепро- ектировать и переписать фрагмент кода.
24.5. Стратегии рефакторинга
Число видов рефакторинга, выгодных для любой конкретной программы, прак- тически бесконечно. Рефакторинг подчиняется тому же закону снижения выго- ды, что и другие процессы программирования, и к нему также относится прави- ло 80/20. Тратьте время на 20% видов рефакторинга, обеспечивающих 80% выго- ды. При определении наиболее важных видов рефакторинга учитывайте следую- щие советы.
Выполняйте рефакторинг при создании новых методов Создавая метод,
проверьте, хорошо ли организованы связанные с ним методы. При необходимо- сти выполните их рефакторинг.
Выполняйте рефакторинг при создании новых классов Создание нового класса часто подчеркивает недостатки имеющегося кода. Используйте эту возмож- ность для рефакторинга других классов, тесно взаимодействующих с новым классом.
Выполняйте рефакторинг при исправлении дефектов Используйте знания,
полученные при исправлении ошибки, для улучшения других фрагментов кода,
которые могут быть подвержены похожим ошибкам.
Выполняйте рефакторинг модулей, подверженных ошибкам Некоторые модули более подвержены ошибкам, чем другие. Есть ли в коде фрагмент, внуша- ющий страх вам и всем остальным членам вашей группы? Скорее всего он под-
Не реализуйте какую-то воз- можность частично, намерева- ясь позднее завершить ее в процессе рефакторинга.
Джон Манзо (John Manzo)
Крупномасштабный рефакто- ринг — путь к катастрофе.
Кент Бек (Kent Beck)