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

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

Операция кажется слишком простой, чтобы создавать для нее метод

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

Небольшие методы обеспечивают несколько преимуществ, и одно из них - облегчение чтения кода. Так, однажды я обнаружил следующую строку примерно в десятке мест программы:

Пример вычисления (псевдокод)

points = deviceUnits * ( POINTS PER INCH / DeviceUnitsPerInch() )

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

Пример вычисления, преобразованного в функцию (псевдокод)

Function DeviceUnitsToPoints ( deviceUnits Integer ): Integer DeviceUnitsToPoints = deviceUnits *

( POINTS PER INCH / DeviceUnitsPerlnchO ) End Function

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

Пример вызова функции (псевдокод)

points = DeviceUnitsToPoints( deviceUnits )

Эта строка более понятна и даже кажется очевидной.

Данный пример позволяет назвать еще одну причину создания отдельных методов для простых операций: дело в том, что простые операции имеют свойство усложняться с течением времени. После того как я написал метод DeviceUnitsPerlnchO, оказалось, что в определенных условиях при активности определенных устройств он возвращает 0. Для предотвращения деления на О мне пришлось написать еще три строки кода:

Пример кода, расширяющегося при сопровождении программы (псевдокод)

Function DeviceUnitsToPoints( deviceUnits: Integer ) Integer; if ( DeviceUnitsPerlnchO <> 0 )

DeviceUnitsToPoints = deviceUnits *

( POINTS PER INCH / DeviceUnitsPerlnchO )



else

DeviceUnitsToPoints = О end if End Function

Если бы в коде по-прежнему использовалась первоначальная строка, мне пришлось бы повторить проверку десять раз, добавив в общей сложности 30 строк кода. Создание простого метода позволило уменьшить это число до 3.

Резюме причин создания методов

Вот список разумных причин создания методов:

снижение сложности;

формирование понятной промежуточной абстракции;

предотвращение дублирования кода;

поддержка наследования;

сокрытие очередности действий;

сокрытие операций над указателями;

улучшение портируемости;

упрощение сложных булевых проверок;

повышение быстродействия.

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

изоляция СЛОЖНОСТИ;

сокрытие деталей реализации;

ограничение влияния изменений;

сокрытие глобальных данных;

создание центральных точек управления;

облегчение повторного использования кода;

выполнение специфического вида рефакторинга.

7.2. Проектирование на уровне методов

Идею связности впервые представили Уэйн Стивене, Гленфорд Майерс и Ларри Константайн (Stevens, Myers, and Constantine, 1974). На уровне проектирования классов ее практически вытеснили более современные концепции, такие как абстракция и инкапсуляция, однако на уровне проектирования отдельных методов эвристический принцип связности по-прежнему полезен.

В случае методов связность характеризует соответствие Нереирветал ссынк» О сшжь выполняемых в методе операций единой цели. Некоторые тй см. подраэдея «Стремитесь программисты предпочитают использовать термин «сила» к максимальной связности» (strength): насколько сильно связаны операции в методе? На- радела 5.3, пример, метод CosineQ (косинус) имеет одну четко определенную цель и потому обладает прекрасной связностью. Метод CosineAndTanQ (косинус и тангенс) имеет меньшую связность, потому что он выполняет сразу



две функции. Наша цель в том, чтобы каждый метод эффективно решал одну задачу и больше ничего не делал.

Вознаграждением будет более высокая надежность кода. В одном исследовании 450 методов было обнаружено, что дефекты отсутствовали в 50% методов, обладающих высокой связностью, и только в 18% методов с низкой связностью (Card, Church, and Agresti, 1986). Другое исследование 450 методов (это просто совпадение, хотя и весьма необычное) показало, что в сравнении с методами, имеющими самое низкое отношение «сопряжение/связность» (coupling-to-cohesion), методы с максимальным отношением «сопряжение/связность» содержали в 7 раз больше ошибок, а исправление этих методов было в 20 раз более дорогим (Selby and Basili, 1991).

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

Функциональная связность - самый сильный и лучший вид связности; она имеет место, когда метод выполняет одну и только одну операцию. Примерами методов, обладающих высокой связностью, являются методы sin() (синус), GetCusto-merNameQ (получить фамилию заказчика), EraseFileQ (удалить файл), Calculate-LoanPaymentQ (вычислить плату за кредит) и AgeFromBirtbdateQ (определить возраст по дате рождения). Конечно, такая оценка связности предполагает, что эти методы соответствуют своим именам - иначе они имеют неудачные имена, а об их связности нельзя сказать ничего определенного.

Ниже описаны другие виды связности, которые обычно считаются менее эффективными.

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

Примером метода с последовательной связностью является метод, вычисляющий по дате рождения возраст сотрудника и срок до его ухода на пенсию. Если метод вычисляет возраст и затем использует этот результат для нахождения срока до ухода сотрудника на пенсию, он имеет последовательную связность. Если метод находит возраст сотрудника, после чего в абсолютно другом вычислении определяет срок до ухода на пенсию, применяя те же данные о дате рождения, он имеет только коммуникационную связность. Как сделать такой метод функционально связным? Создать два отдельных метода: метод, вычисляющий по дате рождения возраст сотрудника, и метод, определяющий по дате рождения срок до ухода сотрудника на пенсию. Второй метод мог бы вызывать метод нахождения возраста. Оба этих метода имели бы функциональную связность. Другие методы могли бы вызывать любой из них или оба.

Коммуникационная связность (communicational cohesion) имеет место, когда выполняемые в методе операции используют одни и те же данные и не связаны между собой иным образом. Если метод печатает отчет, после чего заново инициализи-



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.0088