14.3 Пример объекто-ориентированного проекта

Предыдущая  Содержание  Следующая V*D*V

Графические интерфейсы пользователя (GUI, Graphical User Interface) любимая всеми основа для демонстрации силы объектно-ориентированных подходов. Типичной проверкой будет создание небольшого калькулятора, которым можно управлять щелчками мыши или с клавиатуры:

 

OOC_Object-Oriented_Design_by_Example

 

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

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

У нашего калькулятора есть кнопки, микросхему для вычислений и экран. Экран обеспечивает приём информации: он получает что-то и выводит на экран. Микросхема для вычислений — фильтр информации: она что-то получает, изменяет своё состояние и передаёт изменённую информацию. Кнопка — источник информации или даже фильтр: при правильной обработке она будет передавать информацию.

К настоящему времени мы идентифицировали по крайней мере четыре класса объектов: экран, микросхему для вычислений, кнопки и информацию, передаваемую между ними. Может быть пятый вид объекта, а именно, источник нажатия для кнопки, которая моделирует нашу клавиатуру, мышь, и так далее

Есть общий аспект, который подходит некоторым из этих классов: экран, микросхема для вычислений или кнопка могут быть присоединены к одному общему объекту, а информация передана вдоль этого соединения. Приёмник информационный, подобный экрану, только получает информацию, но это никак не вредит общей картине. Так что мы получаем следующую конструкцию:

 

КЛАСС

ДАННЫЕ

МЕТОДЫ

 

Object

 

 

базовый класс

 

 

 


  Event

 

 

информация для передачи

 

kind

 

 тип данных

 

data

 

 текст, позиция, и так далее

 

 

 


  Ic

 

 

базовый класс приложения

 

out

 

 объект "я связан с"

 

 

wire

 соединяет данный объект с другим объектом

 

 

gate

 отсылает информацию в out

 

 

 


    LineOut

 

 

модель экрана

 

 

wire

 не используется

 

 

gate

 выводит на экран поступающую информацию

 

 

 


    Button

 

 

модель устройства ввода

 

text

 

 метка, определяет интересующую информацию

 

 

gate

 просматривает поступающую информацию:

 если она соответствует text, отсылает её

 

 

 


    Calc

 

 

модуль для вычислений

 

state

 

 текущее значение и тому подобное

 

 

gate

 изменяет состояние на основе информации,

 передаёт новое текущее значение, если таковое имеется

 

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

 

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(). Мог бы помочь ещё один класс:

 

КЛАСС

ДАННЫЕ

МЕТОДЫ

 

Object

 

 

базовый класс

 

 

 


  Ic

 

 

базовый класс приложения

 

 

 


    Mux

 

 

мультиплексор, один вход — много выходов

 

list

 

 список объектов

 

 

wire

 соединяет данный объект с другим объектом

 

 

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, где большая часть элементов информационного потока, даже относящиеся к приложению классы, могут быть '"соединены проводом" перетаскиванием мыши при разработке графического интерфейса пользователя с помощью графического редактора.

 

Предыдущая  Содержание  Следующая