2010-09-09 3 views
1

Я знаю и понимаю, что глобальные переменные и магические числа избегают при программировании, особенно по мере увеличения количества кода в вашем проекте. Однако я не могу придумать хороший способ избежать обоих.Как избежать как глобальных переменных, так и магических чисел?

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

doSomethingWithValue(1920); 

Но это волшебное число. Но чтобы этого избежать, я бы сделал ...

const int SCREEN_WIDTH = 1920; 

//In a later file... 
extern const int SCREEN_WIDTH; 
doSomethingWithValue(SCREEN_WIDTH); 

И теперь я использую глобальную переменную. Какое решение здесь?

+2

Так что я слышу, что глобальные константы обычно в порядке, это глобальные переменные, которые вызывают реальные проблемы. Спасибо, парни! – Lewis

ответ

11

В вашем втором примере, SCREEN_WIDTH на самом деле не переменная , это именованная константа. Нет ничего плохого в использовании именованной константы вообще.

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

1. Технически, да, это «переменная», но это имя не является «правильным», поскольку оно никогда не меняется.

+0

Итак, глобальные переменные являются точными, если они объявлены как const? – Lewis

+1

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

+0

@ Lewis, названная константа может быть соответствующим образом скопирована с помощью скобок "{}". Ваш фрагмент кода не указывает, где объявлена ​​именованная константа. Поместите его в самый высокий объем, но не выше. – user122302

1

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

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

1

Их нужно определить где-то. Почему бы не поставить определения в файле .h или в файле сборки?

2

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

Затем вы просто берете это значение и передаете его туда, где это необходимо.

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

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

Глобальные константы, как правило, прекрасные. Проблема возникает, когда у вас есть mutable глобальное состояние: объекты, к которым можно получить доступ по всему приложению, и которые могут иметь другое значение в зависимости от , когда вы смотрите.Это затрудняет рассуждение и вызывает ряд проблем.

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

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

1

Это не переменная, это константа, которая во время компиляции.

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

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

1

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

Другой пост, который может help

+0

Как это хорошая идея? – alternative

+0

Непонятный вопрос с моей стороны. Я имел в виду глобальные переменные, и вопрос касался значения const. Извиняюсь. – skimobear

5

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

1

В то время как глобальный во втором случае является довольно безобидным, если вы не проектируете это для чего-то, где вы находитесь , обязательно ширина экрана не изменится, я бы использовал что-то, чтобы получить ширину экрана динамически (например, GetSystemMetrics на Windows, или XDisplayWidth на X).

1

Одним из способов избежать этого было бы настроить вашу программу как объект и иметь свойство объекта (my_prog.screen_width). Для запуска вашей программы, main() создайте экземпляр объекта и вызовите метод -> go на объекте.

Java делает это. Много. Половинная идея.

Bonus возможность для расширения вашей программы:

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

Это не огромная сделка для быстрой одноразовой программы.

0

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

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

При разработке класса, имеющего виртуальное свойство readonly, которое возвращает неизменяемое значение, позволит будущим расширениям класса возвращать разные значения. Использование свойства, а не константы может иметь некоторые последствия для производительности, но в некоторых случаях гибкость будет стоить того. Было бы неплохо, если бы существовал способ определения виртуальных констант, и я не вижу причин, по которым теоретически невозможно было бы .net разрешить его (включая константные значения в таблице с указателями виртуальных методов), но пока Я знаю, что это не так.

Смежные вопросы