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

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

А вот код вызывающего метода с глобальной переменной в качестве аргумента:

Пример вызова метода с аргументом, демонстрирующим проблему псевдонимов (Visual Basic)

WriteGlobal( globalVar )

Поскольку inputVar инициализируется О, и WriteGlobalQ добавляет 5 к inputVar, чтобы получить новое значение globalVar, вы ожидаете, что globalVar будет на 5 больше, чем inputVar. Но вот неожиданный результат:

Результат проблемы с псевдонимами

Input Variable: 5 Global Variable: 5

Хитрость в том, что globalVar и inputVar - на самом деле одна и та же переменная! Поскольку globalVar передается в WriteGlobalQ вызывающим методом, к ней обращаются с помощью двух разных имен. Поэтому результат вызовов MsgBoxQ отличается от ожидаемого: они показывают одну и ту же переменную дважды, хотя и используют два разных имени.

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

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

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

Проблемы с неопределенным порядком инициализации глобальных данных

Порядок, в котором данные из разных «единиц трансляции» (файлов) будут инициализироваться, в некоторых языках программирования (в частности, С++) не определен. Если при инициализации глобальной переменной из одного файла



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

Эта проблема решается с помощью обходного маневра, описанного в правиле 47 книги Скотта Мейерса «Effective С++» (Meyers, 1998). Но изощренность решения как раз и иллюстрирует ту излишнюю сложность, которую привносят глобальные данные.

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

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

Причины для использования глобальных данных

Ревнители чистоты данных иногда утверждают, что программисты никогда не должны использовать глобальные данные. Но большинство программ работают с «глобальными данными» в широком смысле этого слова. Записи в базе данных являются глобальными, так же как и данные конфигурационных файлов, например реестра Windows. Именованные константы - это тоже глобальные данные, хотя и не глобальные переменные.

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

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

Эмуляция именованных констант Хотя С++, Java, Visual

„ . \ Щщтш ссыш Об йшно-

Basic и большинство современных языков поддерживают данных константах ш. раздвл127 именованные константы, некоторые языки, такие как Python, Perl, Awk и язык сценариев UNIX, до сих пор - нет. Вы можете использовать глобальные переменные как подстановки для именованных констант, если ваш язык их не поддерживает. Так, вы можете заменить константные значения 1 и О глобальными переменными TRUE и FALSE, установленными в i и 0. Или вы можете заменить число 66, используемое как число строк на странице, переменной LINES PERPAGE = 66. Этот подход позволяет упростить дальнейшее изменение кода, кроме того, его легче читать. Такое упорядоченное применение



глобальных данных - отличный пример программирования с использованием языка, а не на языке (см. раздел 34.4).

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

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

Исключение бродячих данных Иногда вы передаете данные методу или классу только для того, чтобы передать в другой метод или класс. Например, у вас может быть объект-обработчик ошибок, применяемый в каждом методе. Если метод в середине цепочки вызовов не использует этот объект, он называется «бродячим» (tramp data). Применение глобальных переменных помогает исключить бродячие данные.

Используйте глобальные данные только как последнее средство

Прежде чем вы решите использовать глобальные данные, рассмотрите следующие альтернативы.

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

Различайте глобальные переменные и переменные-члены класса Некоторые переменные действительно глобальны в том плане, что к ним обращаются из любого места программы. Другие - на самом деле классовые переменные - интенсивно используются только некоторым© набором методов. Вполне нормально обращаться к классовой переменной из нескольких методов сколь угодно интенсивно. Если методу вне класса нужно использовать эту переменную, предоставьте ее значение посредством метода доступа. Не обращайтесь к членам класса напрямую (как если бы эти переменные были глобальными), даже если ваш язык программирования это позволяет. Этот совет равносилен высказыванию «Модуляри-зируйте! Модуляризируйте! Модуляризируйте!».

Используйте методы доступа Создание методов доступа - основной подход для решения проблем с глобальными данными (см. следующий раздел).



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