Программирование >>  Решение нетривиальных задач 

1 ... 15 16 17 [ 18 ] 19 20 21 ... 77


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 )



1 ... 15 16 17 [ 18 ] 19 20 21 ... 77

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика