14.3 Пример объекто-ориентированного проекта |
Предыдущая Содержание Следующая |
Графические интерфейсы пользователя (GUI, Graphical User Interface) любимая всеми основа для демонстрации силы объектно-ориентированных подходов. Типичной проверкой будет создание небольшого калькулятора, которым можно управлять щелчками мыши или с клавиатуры:
Мы создадим такой калькулятор для curses и менеджеров экрана X11. Для проектирования, реализации и проверки общего решения мы используем объектно-ориентированный подход. Как только всё заработает, мы соединим его с двумя абсолютно несовместимыми графическими средами. В должное время мы увидим, как изящно может использоваться передача сообщений. Это помогает получить работающий алгоритм приложения прежде, чем мы займёмся библиотекой GUI. Это также помогает разложить работу приложения на взаимодействующие объекты. Поэтому давайте просто посмотрим, какие объекты можем идентифицировать в калькуляторе, изображение которого показано выше. У нашего калькулятора есть кнопки, микросхему для вычислений и экран. Экран обеспечивает приём информации: он получает что-то и выводит на экран. Микросхема для вычислений — фильтр информации: она что-то получает, изменяет своё состояние и передаёт изменённую информацию. Кнопка — источник информации или даже фильтр: при правильной обработке она будет передавать информацию. К настоящему времени мы идентифицировали по крайней мере четыре класса объектов: экран, микросхему для вычислений, кнопки и информацию, передаваемую между ними. Может быть пятый вид объекта, а именно, источник нажатия для кнопки, которая моделирует нашу клавиатуру, мышь, и так далее Есть общий аспект, который подходит некоторым из этих классов: экран, микросхема для вычислений или кнопка могут быть присоединены к одному общему объекту, а информация передана вдоль этого соединения. Приёмник информационный, подобный экрану, только получает информацию, но это никак не вредит общей картине. Так что мы получаем следующую конструкцию:
Это выглядит достаточно хорошо для декларации основных методов и попытки написать основную программу, чтобы протестировать разложение нашего проблемного мира на классы.
Ic.d
enum react { reject, accept };
% IcClass: Class Ic: Object { void * out; %- void wire (Object @ to, _self); enum react gate (_self, const void * item); %}
% IcClass LineOut: Ic { %}
% IcClass Button: Ic { const char * text; %}
run.c
int main () { void * calc = new(Calc()); void * lineOut = new(LineOut()); void * mux = new(Mux()); static const char * const cmd [] = { "C", "Q", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "-", "*", "/", "=", 0 };
const char * const * cpp;
wire(lineOut, calc); for (cpp = cmd; * cpp; ++ cpp) { void * button = new(Button(), * cpp);
wire(calc, button), wire(button, mux); }
Конец. Мы можем подготовить микросхему для вычислений, экран и любое количество кнопок, и соединить их. Однако, если мы захотим протестировать этот набор вводом символов с клавиатуры, то должны будем обернуть каждый символ в Event и предложить его каждому объекту Button, пока какой-то не заинтересуется им, и не вернёт accept, когда мы вызываем его метод gate(). Мог бы помочь ещё один класс:
Основная программа, уже показанная выше, использует объект Mux и соединяет его с каждым объектом Button. Мы готовы к основному циклу:
while ((ch = getchar()) != EOF) if (! isspace(ch)) { static char buf [2]; void * event;
buf[0] = ch; gate(mux, event = new(Event(), 0, buf)); delete(event); } return 0; }
Пробелы игнорируются. Любой символ заворачивается в объект события Event с параметром kind равным нулю и символом в виде строки. Событие передаётся для обработки мультиплексору и начинается вычисление. ВыводыЭтот проект был мотивирован техникой Класс-Ответственность-Кооперация (событийное взаимодействие классов, Class-Responsibility-Collaborator), описанным в [Bud91]: рассмотрев задачу, мы определяем более или менее подходящие объекты. Объекту поручается выполнение определённых обязанностей. Это приводит к другим объектам, которые сотрудничают с ним при выполнении работы. Как только объекты известны, они собираются в классы и, надо надеяться, может быть найден иерархический шаблон, который глубже, чем один уровень. Ключевая идея для этого приложения — класс Ic с возможностью получения, изменения и маршрутизации информации. Эта идея была навеяна Interface Builder из NeXTSTEP, где большая часть элементов информационного потока, даже относящиеся к приложению классы, могут быть '"соединены проводом" перетаскиванием мыши при разработке графического интерфейса пользователя с помощью графического редактора.
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Предыдущая Содержание Следующая |