Анимация
JavaScript


Главная  Библионтека 

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

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.position = I AM LEFT CHILD;

if( t.position == I AM LEFT CHILD )

может быть упрощена подобным образом*: struct tnode

unsigned is left child ;

struct tnode *left,

*right;

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 =l}; Нужно показать значения,

enum { UNSCROLLABLE=0; SCROLLABLE =1}; или create window()

enum { NORMAL SIZE =0; MAXIMIZED =l}; не будет работать. ...

create window( BORDERED, UNSCROLLABLE, MAXIMIZED );

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

if( has border == BORDERED )

...

сравнивая его с более простым:

if ( has border ) ...



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