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

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

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

Размеры структур данных Объявляя массив из 100 элементов, вы раскрываете информацию, которую никто знать не должен. Защищайте право на личную жизнь! Сокрытие информации не всегда требует создания целого класса. Иногда для этого достаточно именованной константы: например, MAXEMPLOYEES позволяет скрыть число -100.

Предвосхищение изменений разного масштаба

Щщтги есыш Расшат- Обдумывая потенциальные изменения системы, проектируйте риваемый в зтом разделе под- " чтобы влияние изменений было обратно пропорци-ход к предвосхищению измене- опально их вероятности. Если вероятность изменения высока, нийнесвязансзаблаговремен- убедитесь, что систему будет легко адаптировать к нему ным проектированием или ко- q большим влиянием на несколько классов системы можно «Програмш содержиткод смириться лишь в случае крайне маловероятных изменений, торый может когда-нибудь по- Грамотные проектировщики также принимают во внимание надобиться» раздела 24.2). цену предвосхищения изменений. Если изменение маловероятно, но его легко предугадать, рассмотрите его внимательнее, чем более вероятное изменение, которое трудно спла-Домштедьные шдеш Это обсуждение основано на подхо-

де, описанном в статье «Оп the Один хороший метод определения областей вероятных deslpanddevefopmentof prog- изменений подразумевает, что вы должны сначала опреде-ram families> (Parnas, 1976). минимальное подмножество фрагментов программы,

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

Поддерживайте сопряжение слабым

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



зывают «слабым сопряжением» (loose coupling)». В контекстах классов и методов концепция сопряжения одна и та же, так что при обсуждении сопряжения буду называть методы и классы «модулями».

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

Старайтесь создавать модули, слабо зависящие от других модулей. Отношения модулей должны напоминать отношения деловых партнеров, а не сиамских близнецов. Скажем, метод sinQ (синус) сопряжен слабо, так как нужную информацию он получает в форме одного значения - угла в градусах. Метод InitVars ( шг7, var2, var3,varN ) сопряжен жестче, поскольку многие детали его работы становятся известными вызывающему модулю по передаваемым значениям. Два класса, зависящих от того, как каждый из них использует одну глобальную переменную, сопряжены еще жестче.

Критерии оценки сопряжения

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

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

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

Гибкость Гибкость характеризует легкость изменения связи между модулями. Идеальная связь должна быть как можно гибче. Гибкость частично определяется другими аспектами связанности, но в то же время отличается от них. Положим, у вас есть метод LookupVacationBenefitO, определяющий длительность отпуска сотрудника на основании даты его приема на работу и должности. Допустим далее, что в другом модуле у вас есть объект employee (сотрудник), содержащий, помимо всего прочего, информацию о должности и дате приема на работу, и что этот модуль передает объект employee в метод LookupVacationBenefitO-



С точки зрения других критериев, эти два модуля кажутся слабо сопряженными: связь двух модулей посредством объекта employee очевидна и является единственной. Теперь предположим, что вам нужно использовать модуль LookupVacationBe-nefitQ из третьего модуля, владеющего информацией о дате приема сотрудника на работу и его должности, но хранит ее не в объекте employee. В этот момент моцуъ LookupVacationBenefitO начинает вести себя гораздо менее дружелюбно, не желая связываться с новым модулем.

Чтобы третий модуль мог обратиться к модулю LookupVacationBenefltO, он должен знать о существовании класса Employee. Он мог бы подделать объект employee, используя лишь два поля, но тогда он должен был бы знать внутренние детали работы метода LookupVacationBeneJitQ: ему была бы необходима уверенность в том, что метод LookupVacationBenefitO использует только два этих поля. Такое решение было бы небрежным и безобразным. Второй вариант мог бы заключаться в таком изменении метода LookupVacationBenefitO, чтобы вместо объекта employee он принимал должность сотрудника и дату его приема на работу. В обоих случаях первоначальный модуль оказывается на самом деле гораздо менее гибким, чем казалось сначала.

Возможен и счастливый конец этой истории: недружелюбный модуль сможет завести друзей, если пожелает быть гибким - если вместо объекта employee он согласится принимать должность и дату приема сотрудника на работу.

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

Виды сопряжения

Самые распространенные виды сопряжения описаны ниже.

Простое сопряжение посредством данных-параметров Два модуля сопряжены таким способом, если между ними передаются только элементарные типы данных, причем передаются через списки параметров. Этот вид сопряжения нормален и приемлем.

Простое сопряжение посредством объекта Модуль сопряжен с объектом этим способом, если он создает экземпляр данного объекта. С этим видом сопряжения также все в порядке.

Сопряжение посредством объекта-параметра Два модуля сопряжены друг с другом объектом-параметром, если Объект 1 требует, чтобы Объект 2 передал ему Объект 3. Этот вид сопряжения жестче, чем тот вид, при котором Объект 1 требует от Объекта 2 только примитивных типов данных, потому что Объект 2 должен обладать информацией об Объекте 3.

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



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