Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
книги хакеры / Питер_Гудлиф_Ремесло_программиста_Практика_написания_хорошего_кода.pdf
Скачиваний:
16
Добавлен:
19.04.2024
Размер:
9.23 Mб
Скачать

 

 

 

 

hang

e

 

 

 

 

 

 

C

 

E

 

 

 

X

 

 

 

 

 

-

 

 

 

 

 

d

 

F

 

 

 

 

 

 

t

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

to

 

 

 

 

w Click

 

 

 

530m

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

.

 

 

 

 

 

.c

 

 

p

 

 

 

 

g

 

 

 

 

df

 

 

n

e

 

 

 

 

-xcha

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

Глава 22. Рецепт программыClick

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

окончательного срока. Вынуть, вывалить и дать остыть, перед тем как подавать клиенту.

Мне известно, по крайней мере, четыре рецепта бисквита. Их разли% чия определяются вашими предпочтениями – хотите ли вы бисквит без масла или бисквит без яиц – и способом приготовления. Програм% мы пишутся таким же образом. Не существует рецепта или магиче% ской формулы; одну и ту же систему можно построить разными спосо% бами, каждый из которых может быть не лучше другого. Можно вы% брать разные ингредиенты для процесса разработки и разные методы. Так или иначе, в результате могут испечься немного различающиеся пироги – в отношении функций, структуры, стабильности, расширяе% мости, сопровождаемости и т. п. Рецепты описывают жизненный цикл программного продукта: этапы разработки от первоначального (замы% сел программы) до окончательного (прекращения эксплуатации).

Мы, программисты, должны предсказуемым (и в какой%то мере воспро% изводимым) образом создавать программное обеспечение, следуя опре% деленной процедуре. Мы должны привлечь себе на помощь такую про% цедуру разработки, которая позволит нам создавать лучшие из возмож% ных программ. В этой главе мы изучим некоторые рецепты создания программ; мы будем их сравнивать, противопоставлять, критиковать и смотреть, какое влияние они оказывают на создаваемый нами код.

Мы писали программы для ZX spectrum не так, как для современного наладонного PDA, и не так, как систему биржевого контроля для мэйнфрейма с высокопроизводительным веб%интерфейсом. В одиноч% ку мы программируем иначе, чем в паре, и иначе, чем в команде из 200 человек. Выбор рецепта определяется различиями в целевой плат% форме и команде разработчиков (и их уровне мастерства). Искусство программирования не ограничивается работой с редактором, компи% ляцией, сборкой и запуском.

Хорошие программисты знают, как программировать – владеют методами и приемами работы.

Каковы же эти рецепты программирования?

Стили программирования

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

Разным языкам программирования соответствуют разные стили про% граммирования. Одни стили подогнаны под конкретный язык, другие

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

Стилиm

программирования

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

531Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

подходят для нескольких. Стили программирования делятся на две главные категории: процедурные и описательные.

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

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

Выбор языка программирования отчасти определяет стиль. (Лучше все же выбирать язык, поддерживающий тот стиль, который вы хоти% те использовать.) Однако выбор языка программирования – не самое главное. Вполне можно писать структурированный код на объектно% ориентированном языке, точно так же, как можно написать отврати% тельный код на любом языке. В нескольких последующих разделах описываются популярные стили программирования.

Структурное программирование

В этом стандартном методе процедурного проектирования применяет% ся алгоритмическая декомпозиция – процесс разбиения системы на части, каждая из которых представляет собой небольшой шаг в более крупном процессе. Проектные решения направлены на поток управле% ния и создают иерархическую функциональную структуру. Как писал Дейкстра: «Иерархические системы обладают тем свойством, что сущ% ность, считающаяся неделимой на одном уровне, рассматривается как составной объект на следующем, более низком уровне детализации; в результате естественные гранулы пространства или времени, приме% нимые на каждом уровне, уменьшаются на порядок, когда мы пере% ключаем свое внимание на очередной более низкий уровень. Мы гово% рим о стенах в терминах кирпичей, о кирпичах – в терминах кристал% лов, о кристаллах – в терминах молекул, и т. д.» Так Дейкстра попу% ляризировал структурное программирование в своей классической статье «Go To Statement Considered Harmful» (Оператор Go To вреден). (Dijkstra 68)

Структурное программирование – это модель, сосредоточенная на управ% лении и следующая нисходящей модели проектирования. Вы начина% ете с того, что задумываете целиком всю программу (например, сде лать_покупки), потом разлагаете ее в серию подблоков (например, соста вить_список_покупок, выйти_из_дома, дойти_до_магазина, выбрать_покупки, рас платиться_в_кассе, вернуться_домой). В свою очередь каждый подблок раскладывается на части, пока не будет достигнут такой уровень, на котором легко написать реализацию в коде. Блоки собираются в це% лое, и на этом проект заканчивается.

 

 

 

 

hang

e

 

 

 

 

 

 

C

 

E

 

 

 

X

 

 

 

 

 

-

 

 

 

 

 

d

 

F

 

 

 

 

 

 

t

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

to

 

 

 

 

w Click

 

 

 

532m

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

.

 

 

 

 

 

.c

 

 

p

 

 

 

 

g

 

 

 

 

df

 

 

n

e

 

 

 

 

-xcha

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

Глава 22. Рецепт программыClick

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Структурный подход имеет следующие последствия:

Каждый шаг декомпозиции должен быть в пределах разумного по% нимания программистом. (Дейкстра сказал: «Я предлагаю ограни% читься проектированием и реализацией программ, понимаемых ра% зумом».)

Поток управления нужно тщательно контролировать: избегайте ужасного оператора goto (неструктурированного перехода в произ% вольное место программы) и пишите функции с одним входом и од% ним выходом (так называемый код SESE).

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

Распространенные языки структурного программирования – C, Pascal, BASIC и более древние, типа Fortran и COBOL. С помощью большинст% ва процедурных языков легко пишется структурный код, хотя это не их специализация; структурные программисты часто принимают но% вомодные языки, не принимая новых идиом.1

ОбъектноNориентированное программирование

Буч так описывает ОО%программирование: «Метод реализации, при котором программы организованы в виде взаимодействующих между собой объектов, каждый из которых представляет собой экземпляр не% которого класса, а классы образуют иерархическую структуру, осно% ванную на отношениях наследования.» (Booch 94) Это тоже процедур% ный стиль, но он позволяет более естественным способом моделировать реальность; мы направляем свое внимание на моделируемые взаимо% действующие сущности, а не на конкретный поток выполнения.

Эта модель в значительной степени строится вокруг данных (в отличие от структурного программирования, где в центре находятся процес% сы). Мы интересуемся здесь жизнью данных и их перемещением, а не последовательностью действий, которые нужно выполнить, чтобы ре% шить задачу. У объектов (данных) есть поведение (они что%то делают) и состояние (которое изменяется в результате действий). На уровне языка это реализовано в виде методов классов объектов. ОО%програм% мы рассматриваются как наборы взаимодействующих программных компонент, а не монолитные списки команд ЦП. ОО%проектирование позволило нам эффективно моделировать крупные системы.

В объектно%ориентированном программировании применяются сле% дующие понятия компьютерной науки:

1Это необязательно плохо, если только программист не считает, что вышел за границы структурного кодирования, не меняя своего способа разработки

кода.

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

Стилиm

программирования

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

533Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Абстракция

Абстракция – как искусство избирательно уделять внимание – по% зволяет проектировать код так, что верхние уровни управления мо% гут игнорировать конкретные детали реализации. Не все ли равно, что происходит при обращении к get_next_item – бинарный поиск по дереву, выбор элемента массива или телефонный звонок во Франк% фурт? Важно, что возвращается очередной элемент (чем бы он ни был), и вызывающему коду больше ни о чем беспокоиться не нужно.

Представление Дейкстрой иерархии (вернитесь к нему и прочтите снова) открыло определенный вид абстракции.

Инкапсуляция

Инкапсуляцией называют помещение связанных друг с другом ис% полняемых блоков в один пакет, доступ к которому осуществляется только через четко определенный API: капсулу для кода. Пользова% тели этой капсулы могут лишь обращаться к заданному API, но не имеют прямого доступа к внутреннему состоянию. Это обеспечивает четкое разделение обязанностей, дает возможность порассуждать над метафизическими вопросами типа «Что есть объект?» и дает некоторые гарантии того, что никакой злоумышленник не сможет поковыряться в вашем коде, когда вы отвернетесь.

Наследование

Это механизм для создания объектов, являющихся особой версией родительских. Пусть родительский тип называется Фигура, а насле% дуют ему Квадрат, Круг и Треугольник. Наследники обладают более де% тальным и специализированным поведением (например, они знают, сколько сторон у фигуры). Как и любые идеи в программировании, наследование может служить основой для создания непонятных и странных программ, а может применяться в логически правиль% ном, элегантном коде. Хорошие ОО%программисты умеют создавать эффективные наследственные иерархии.

Полиморфизм

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

Динамический полиморфизм в соответствии со своим названием определяет фактическую операцию на этапе исполнения – в зависи% мости от типа операнда или целевого объекта. При этом часто ис% пользуется иерархия наследования: клиент, работающий с типом Фигура, может в конкретном случае работать с объектами типа Квад рат или Треугольник, что определяется во время прогона.