Главная - Литература

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 [185] 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294

24.3. Отдельные виды рефакторинга

Ниже вы найдете список видов рефакторинга, многие из которых я сформулировал на основе более подробных описаний, приведенных в книге «Refactoring» (Fowler, 1999). Однако я не пытался сделать этот список исчерпывающим. В некотором смысле каждый пример плохого и аналогичного хорошего кода в этой книге претендует на то, чтобы быть видом рефакторинга. Ради экономии места я привел только те виды рефакторинга, которые счел наиболее полезными.

Рефакторинг на уровне данных

Следующие виды рефакторинга связаны с использованием переменных и других видов данных.

Замена магического числа на именованную константу Если вы используете численный или строковый литерал, скажем, 3.i4, замените его именованной константой, такой как PL

Присвоение переменной более ясного или информативного имени Если имя переменной неясно, присвойте ей лучшее имя. Конечно, этот же совет относится и к переименованию констант, классов и методов.

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

Замена выражения на вызов метода Этот вид рефакторинга обычно служит для устранения из кода повторяющихся выражений.

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

Преобразование многоцелевой переменной в несколько одноцелевых переменных Если переменная используется более чем с одной целью (к частым подозреваемым относятся такие переменные, как ij\ temp и х), создайте для каждой из целей отдельную переменную, выбрав для нее более определенное имя.

Использование локальной переменной вместо параметра Если исключительно входной параметр метода служит в качестве локальной переменной, подумайте, не лучше ли создать для этого настоящую локальную переменную.

Преобразование элементарного типа данных в класс Если элементарный тип данных нужно расширить дополнительными формами поведения (например, более строгим контролем типа) или дополнительными данными, преобразуйте его в класс и реализуйте нужное поведение. Это относится и к простым численным типам вроде Afowev и Temperature, и к перечислениям, таким как Color, Shape, Country или OutputType.

Преобразование набора кодов в класс или перечисление В более старых программах часто встречаются фрагменты вида:

const int SCREEN = 0; const int PRINTER = 1; const int FILE = 2;

Вместо определения таких отдельных констант лучше было бы создать класс Output-Type-, это обеспечило бы вам достоинства более строгого контроля типов и по-



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

Преобразование набора кодов в класс, имеющий производные классы Если разные элементы, ассоциированные с разными типами, могут иметь разное поведение, подумайте о создании базового класса для типа и производных классов для каждого кода типа. Так, для базового класса OutputType можно было бы создать подклассы Screen, Printer и File.

Преобразование массива в класс Если элементами массива являются разные типы, создайте класс, включающий поля для каждого элемента массиба.

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

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

Рефакторинг на уровне отдельных операторов

Декомпозиция логического выражения Упростите логическое выражение, введя грамотно названные промежуточные переменные, документирующие суть выражения.

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

Консолидация фрагментов, повторяющихся в разных частях условного оператора Если в конце блока else содержится такой же фрагмент кода, что и в конце блока if, вынесите этот фрагмент за пределы оператора if-tben-else.

Использование оператора break или return вместо управляющей переменной цикла Если для управления циклом используется такая переменная, как done, удалите ее и выполняйте выход из цикла при помощи оператора break или return.

Возврат из метода сразу после получения ответа вместо установки возвращаемого значения внутри вложенных операторов if-then-else Выход из метода сразу же после нахождения возвращаемого значения часто помогает облегчить чтение кода и снизить вероятность ошибок. Альтернативный вариант - установка возвращаемого значения и следование к выходу из метода через заторы операторов - может оказаться более сложным.

Замена условных операторов (особенно многочисленных блоков casej на вызов полиморфного метода Значительную часть логики, обычно включаемой при структурном программировании в блоки case, можно реализовать с помощью наследования в виде полиморфных методов.

Создание и использование «пустых» объектов вместо того, чтобы проверять, равно ли значение null Иногда «пустой» объект должен иметь обоб-



щенное поведение или обобщенные данные, например, определять неизвестного человека как «гражданина». В этом случае подумайте о перемещении ответственности за обработку значений null из клиентского кода в класс, т. е. вместо того, чтобы проверять в клиентском коде класса Customer (заказчик), известно ли имя заказчика, и подставлять значение «гражданин», если оно неизвестно, определите неизвестного заказчика как «гражданина» прямо в классе Customer.

Рефакторинг на уровне отдельных методов

Извлечение метода из другого метода Превратите фрагмент метода в отдельный метод.

Встраивание кода метода Если метод прост и понятен, можете не вызывать его, а встроить его код в программу

Преобразование объемного метода в класс Если метод слишком велик, попробуйте превратить его в класс и разбить на несколько методов. Иногда это повышает удобочитаемость кода.

Замена сложного алгоритма на простой Этот вид рефакторинга пояснений не требует.

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

Удаление параметра Если метод не нуждается в каком-то параметре, удалите его.

Отделение операций запроса данных от операций изменения данных

Как правило, операции запроса данных не должны изменять состояние объекта. Если операция вроде GetTotalsQ (получение итоговой суммы) изменяет состояние объекта, разделите функциональность запроса и функциональность изменения состояния объекта, создав два отдельных метода.

Объединение похожих методов путем их параметризации Два похожих метода могут различаться только используемой в них константой. Объедините их в один метод и передавайте в него нужное значение как параметр.

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

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

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

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



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 [185] 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294



0.0024