Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Kernigan_B__Payk_R_Praktika_programmirovania.pdf
Скачиваний:
76
Добавлен:
18.03.2016
Размер:
2.53 Mб
Скачать

int c;

while ((c = in. read()) != -1) System.out.print((char) c); in.close();

}

catch (FileNotFoundException e)

{

System.err.println(fname + " not found");

}

catch (lOException e)

{

System.err.println("IOException: " + e); e.printStackTrace();

}

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

исключение, а не установка переменной in в null, как это было бы сделано в С или C++. Наконец, если в блоке t ry происходит какая-то другая ошибка ввода, также возбуждается исключение, обрабатываемое в блоке lOException.

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

В С пара функций — setjmp и longjmp — предоставляет возможность реализовать механизм исключений на гораздо более низком уровне, но это настолько сложно, что мы не будем описывать, как это сделать.

Как насчет восстановления ресурсов при возникновении ошибки? Должна ли библиотека предпринимать попытки такого восстановления, если что-то идет не так, как надр? Как правило, нет, однако очень неплохо предусмотреть какой-то механизм, позволяющий удостовериться, что информация сохранилась в максимально корректной форме. Естественно, неиспользуемое пространство памяти должно быть высвобождено. Если же к каким-то, переменным еще возможен доступ, они должны быть установлены в осмысленные значения. Распространенной причиной ошибок является использование указателя на уже освобожденную память. Чтобы не попасться на эту удочку, достаточно в коде обработки ошибки, который высвобождает что-то, установить указатель, адресующийся к этому чему-то, в ноль. Функция reset во второй версии библиотеки CSV как раз и являлась нашей попыткой преодолеть некоторые из описанных проблем. Обобщая же все вышесказанное, отметим: надо добиваться того, чтобы библиотека оставалась пригодна к использованию даже после возникновения ошибки.

Пользовательские интерфейсы

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

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

estrdup failed

когда можно сообщить

markov: estrdup("Derrida") неудача: мало места в памяти

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

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

/* usage: печатает подсказку и выходит */ void usage(void)

{

fprintf(stderr, "usage: %s [-d] [-n nwords]" " [-s seed] [files ...]\n", prognameO); exit(2);

}

Имя программы, вырабатываемое функцией prog name, идентифицирует источник сообщения. Это особенно важно в случае, если программа является частью какогото большого процесса. Если программа будет выводить сообщения вроде syntax error или estrdup failed, то пользователь может просто не понять, откуда пришло сообщение.

Текст сообщений об ошибке, подсказок и окон диалога должен обязательно четко описывать допустимые значения: не утверждайте, что параметр слишком велик, а приведите диапазон допустимых значений для этого параметра. Когда это возможно, текст должен сам по себе являться корректным вводом, например полной командной строкой с правильно заданным параметром. Это не только даст возможность пользователю понять, чего же от него ждут, но и позволит сохранить такой выводимый текст в файле (или "вырезать" его с помощью мыши) и потом использовать для запуска какого-то следующего процесса. Здесь, кстати, сразу становится виден один из недостатков окон диалога: их содержимое довольно трудно запомнить для дальнейшего использования.

Эффективный способ создать хороший пользовательский интерфейс для ввода — спроектировать специализированный язык для установки параметров, контролирования действий и т. п. Интерфейсы, основанные на языках, мы подробно обсудим в главе 9.

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

Большинство людей пользуется сейчас графическими интерфейсами. Графические пользовательские интерфейсы — отдельная большая тема, поэтому мы упомянем лишь о нескольких связанных с ними моментах. Во-первых, графический интерфейс трудно сделать "правильным", поскольку его пригодность и удобство оцениваются пользователями субъективно. Во-вторых, с чисто практической точки зрения в системе с графическим пользовательским интерфейсом размер кода, обрабатывающего взаимодействие с пользователем, как правило, гораздо больше; чем код для любого самого сложного алгоритма.

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

Стандартность и привычность интерфейса крайне желательны; это требование включает в себя последовательное использование терминов, модулей, форматов, шрифтов, цветов, размеров и всех остальных составляющих графическую среду элементов. Сколько различных английских слов используется для выхода из программы или закрытия окна? С десяток — от Abandon до control-Z; подобная непоследовательность может слегка запутать даже пользователя, для которого английский является родным языком, иностранца же она просто заводит в тупик.

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

Дополнительная литература

Несмотря на то что ряд технических деталей, описанных в книге "Мистический человекомесяц" Фредерика Брукса (Frederick P. Brooks, Jr. The Mythical Man Month. Addison-Wesley, 1975; Anniversary Edition, 1995)' уже устарел, она не перестала быть захватывающе интересной . и во многом столь же актуальной сегодня, как и двадцать лет назад.

Практически в каждой книге по программированию есть что-то интересное о проектировании интерфейсов. Практическим пособием, созданным на основе большого, потом и кровью добытого опыта, является книга "Разработка крупномасштабных программ на C++" Джона Лакоса (John Lakos. Large-Scale C++ Software Design. Addison-Wesley, 1996). В этой книге обсуждаются проблемы создания и управления действительно большими программами на C++. В создании программ на С поможет труд Дэвида Хэнсона "Си: интерфейс и реализация" (David Hanson. С Inter/aces and Implementations. Addison-Wesley, 1997).

Отличным рассказом о том, как писать программы в команде, является книга Стива Мак-Коннелла "Быстрая разработка" (Steve McCon-nell's. Rapid Development. Microsoft Press, 1996). В ней, кстати, особое внимание уделяется роли прототипа программы.

О проектировании графических пользовательских интерфейсов написано немало книг, авторы которых затрагивают различные аспекты этого процесса. Мы советуем:

Kevin Mullet, Darrell Sano. Designing Visual Inter/aces: Communication Oriented Techniques. Prentice Hall, 1995;

Ben Shneiderman. Designing the User Inter/асе: Strategies/or Effective HumanComputer Interaction. 3rd ed. Addison-Wesley, 1997;

Alan Cooper. About Face: The Essentials of User Interface Design. IDG, 1995;

Harold Thimbleby. User Interface Design. Addison-Wesley, 1990.

Брукс-мл. Ф. П. Как проектируются и создаются программные комплексы. М.: Наука, 1979; новое издание перевода: Мистический человекомесяц. СПб.:

СИМБОЛ+, 1999.