|
Программирование >> Решение нетривиальных задач
48. Избегайте ненужных идентификаторов Имена для констант часто вообще не нужны. Например, не определяйте значения, возвращаемые при ошибке; если возвращается всего одна ошибка, возвратите просто FALSE. Не делайте так: enum { INSERT ERROR, DELETE ERROR }; insert() ... return INSERT ERROR; delete() { ... return DELETE ERROR; а просто возвратите 0 в случае ошибки и в случае успеха любое правильное значение типа 1. 49. Именованные константы для булевых величин редко необходимы Выбор неверного имени может добавить значительную ненужную сложность в вашу программу. Рассмотрим следующую простейшую функцию, которая подсчитывает количество слов в строке: int nwords(const char *str) typedef enum { IN WORD, BETWEEN WORDS } wstate; int word count = 0; wstate state = BETWEEN WORDS; for(; *str ; ++str ) if( isspace(*str) ) state = BETWEEN WORDS; else if( state != IN WORD ) { ++word count; state = IN WORD; return word count; Неправильно выбранное имя state заставило нас ввести два ненужных * В стандарте ISO/IEC 14882 существует тип bool. Имеет смысл заменить тип переменной is left child на bool. - Ред. идентификатора: IN WORD и BETWEEN WORDS. Теперь взгляните на этот вариант: int nwords2( const char *str) int word count = 0; int in word = 0; for(; *str ; ++str ) { if( isspace(*str) ) in word = 0; else if( !in word ) { ++word count; in word = 1; return word count; Переименование нечетко названной переменной state во что-нибудь, что действительно описывает назначение переменной, позволило мне исключить булевые именованные константы IN WORD и BETWEEN WORDS. Получившаяся подпрограмма меньше и легче читается. Вот другой пример. Следующая программа: enum child type { I AM A LEFT CHILD, I AM A RIGHT CHILD }; struct tnode child type position; struct tnode *left, *right; } t; ... t.position = I AM LEFT CHILD; if( t.position == I AM LEFT CHILD ) ... может быть упрощена подобным образом*: struct tnode unsigned is left child ; struct tnode *left, *right; } t; t.is left child = 1; if( t.is left child ) ... тем самым исключая два ненужных идентификатора. И вот последний пример: enum { SOME BEHAVIOR, SOME OTHER BEHAVIOR, SOME THIRD BEHAVIOR f( SOME BEHAVIOR, x); f( SOME OTHER BEHAVIOR, x); f( SOME THIRD BEHAVIOR, x); требующий четырех идентификаторов (три именованные константы и имя функции). Лучше, хотя это не всегда возможно, исключить селекторную константу в пользу дополнительных функций: some behavior(x); some other behavior(x); some third behavior(x); Обратной стороной этой монеты является вызов функции. Рассмотрим следующий прототип: create window( int has border, int is scrollable, int is maximized ); Я снова выбрал рациональные имена для исключения необходимости в именованных константах. К сожалению, вызов этой функции плохо читаем: create window( TRUE, FALSE, TRUE ); Просто взглянув на такой вызов, я не получу никакого представления о том, как будет выглядеть это окно. Несколько именованных констант проясняют обстоятельства в этом вызове: enum { UNBORDERED =0; BORDERED =1}; Нужно показать значения, enum { UNSCROLLABLE=0; SCROLLABLE =1}; или create window() enum { NORMAL SIZE =0; MAXIMIZED =1}; не будет работать. ... create window( BORDERED, UNSCROLLABLE, MAXIMIZED ); но теперь у меня другая проблема. Я не хочу использовать именованные константы внутри самой create window(). Они здесь только для того, чтобы сделать ее вызов более читаемым, и я не хочу загромождать эту функцию таким кодом, как: if( has border == BORDERED ) ... сравнивая его с более простым: if( has border )
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |