ПРОЕКТ "ИНТЕГРАЦИЯ"



 ПЯТАЯ ГЛАВА

Бучнев А.А., Калантаев П.А., Ким П.А., Пяткин В.П.
ПЕРСПЕКТИВНЫЕ ИНФОРМАЦИОННЫЕ ТЕХНОЛОГИИ В ПРИКЛАДНЫХ ДИСТАНЦИОННЫХ ИССЛЕДОВАНИЯХ ЗЕМЛИ ИЗ КОСМОСА
 
Глава 5. ПОДСИСТЕМА АНАЛИЗА ДАННЫХ И ПОЛЬЗОВАТЕЛЬСКИЙ  ИНТЕРФЕЙС
5.1. Объектно-ориентированный подход к проектированию программных систем
5.2. Языки и системы объектно-ориентированного программирования
5.3. Алгоритмическое и программное обеспечение обработки изображений
5.4. Оконный пользовательский интерфейс
5.5. Программный комплекс для обработки аэрокосмических изображений

        Список литературы

5.1. Объектно-ориентированный подход к созданию программных систем.
Объектно-ориентированное программирование - это основная методология программирования настоящего времени. Она  представляет собой продукт
многолетних практики и опыта, которые восходят к использованию языков Simula 67, затем Smalltalk, Lisp, Clu и не так давно Actor, Eiffel, Objective C , C++, Java. Это стиль программирования, который фиксирует поведение рассужде реального мира таким способом, при котором детали его реализации скрыты. Если подобное удается, то это позволяет тому, кто занимается решением проблемы, вестиния в терминах предметной области [1-2].
Объектно-ориентированное программирование (ООП) - это подход к программированию, сосредоточенный на данных, в котором данные и поведение жестко связаны. Данные и поведение представлены в виде классов, экземпляры которых - объекты. ООП позволяет пользователю вводить собственные типы данных, расширяя тем самым набор встроенных в язык типов данных. Для обозначения этих расширений используется термин абстрактные типы данных (АТД). Они составлены из множества значений и набора операций, которые могут работать с этими значениями. Например, язык С не имеет данных типа "комплексное число", но С++ позволяет добавить такой тип и объединить его с существующими типами. Основными парадигмами  ООП являются инкапсуляция, наследование и полиморфизм.
    Под инкапсуляцией обычно понимается сокрытие данных и операций АТД от
внешних по отношению к этому АТД использующих его программ [3]. Другими словами, инкапсуляция - это возможность скрыть внутренние детали при описании общего интерфейса для типа, определенного пользователем.
    Наследование - это средство получения новых типов данных (классов) из уже существующих типов, называемых базовыми классами. При этом повторно используется существующий код. Порождённый класс образуется из базового путем добавления или изменения кода. Посредством наследования может быть создана иерархия родственных типов, которые совместно используют код и интерфейс. Различают единичное наследование, когда имеется только один базовый класс,
и множественное наследование, когда базовых классов несколько.
    Полиморфизм - средство для придания различных значений одному и тому же сообщению в зависимости от типа обрабатываемых данных. Полиморфная функция имеет множество форм. Например, если в ANSI C аргументы оператора деления
целого типа, то используется целочисленное деление. Если же один или оба
аргумента - значения с плавающей точкой, то используется деление с плавающей точкой.  Таким образом, полиморфная функция вызывается на основании своей сигнатуры, которая определяется списком типов аргументов в перечне параметров функции. При иерархическом наследовании используются также виртуальные (или абстрактные) функции, которые позволяют выбирать соответствующие реализации функции динамически во время выполнения программы. Реализация виртуальной функции базового класса может быть различной в разных классах, порожденных
из базового. Существует также параметрический полиморфизм, который позволяет
один и тот же код использовать для работы с данными различных типов, где
тип - параметр тела кода.
Таким образом, язык ООП должен обеспечивать [2]: Абстрактные типы данных реализуются в ООП с помощью механизма классов.
Классы позволяют программисту управлять видимостью того, что лежит в основе реализации. Сокрытие данных обеспечивается ключевым словом class и ключевыми словами, связанными с правами доступа: public, private и protected. Класс -это
способ инкапсуляции типов данных и связанных с ними функций. Разрешение
частной (private) и общей (public) видимости для членов класса дает программисту возможность управлять тем, какие части структуры данных будут модифицируемы. Private части скрыты от кода пользователя, а public - доступны. Члены класса со статусом доступа protected занимают промежуточное положение: они доступны как внутри класса, так и во всех производных от него классах. Скрытое представление возможно изменить без изменения public доступа и функциональных возможностей. Термин сокрытие информации используется вместо сокрытия данных для того, чтобы подчеркнуть, что и данные и функциональные члены могут быть скрыты. Это приводит к тому, что код пользователя становится более устойчивым, поскольку он не требует изменения при изменении скрытых объектов, от которых зависит.
Определение класса  схематически выглядит следующим образом:
class Имя_класса
  {
     Раздел атрибутов;
     Раздел операций;
  }
    Как только определен класс (тип), например, с именем А, можно говорить
об объектах этого класса (переменных типа А), которые называют также экземплярами класса. Раздел атрибутов предназначен для объявления переменных класса. Они и задают атрибуты объектов класса. Их типы в совокупности задают множество возможных значений или состояний объектов класса. Раздел операций предназначен для объявления и определения операций, которые можно выполнять над объектами класса. В ООП операции часто называют методами класса. Методы описывают поведение объектов класса в результате выполнения операций.
Чтобы скрыть реализацию операций, определение класса разбивается на две части: интерфейс класса и реализацию класса. Интерфейс класса содержит только объявление его элементов: переменных и методов. Определения методов в виде их реализации как функций языка отделены от интерфейса и помещаются в реализацию класса. Достоинство этой схемы в том, что программист может использовать класс, зная его интерфейс и не вдаваясь в детали реализации. Из интерфейса можно понять, какие в классе операции, как их вызывать, какова их семантика. Реализация операций может быть произвольной, лишь бы она соответствовала семантике. Изменение реализации при сохранении интерфейса и семантики не влияет на программы, использующие данный класс. Признаком хорошего стиля считается полное сокрытие данных (переменных класса) с помощью спецификаторов private и protected, означающее,
что доступ к ним возможен только посредством методов данного класса или его наследников, а непосредственный доступ к ним запрещен.
Суть наследования состоит в том, что при создании нового класса его можно
объявить наследником одного или нескольких классов. Пусть уже определен класс А,
и при определении новый класс В объявлен наследником класса А. В этом случае объекты класса В наследуют все свойства и поведение класса А. Значит, в классе В определены переменные и методы класса А. Класс А называется базовым (родительским) по отношению к производному (порожденному) классу В. Ввиду транзитивности наследования каждый класс может иметь множество родителей (предков) и множество потомков, среди которых выделяют "непосредственных родителей" и "непосредственных потомков". Потомок транзитивно наследует свойства и поведение всех своих предков. В производном классе можно не только определить новые свойства и новое поведение, задавая новые переменные и новые методы, но и переопределить существующие методы базового класса.
Отношение наследования обычно представляют в виде графа, узлы которого соответствуют классам, и из узла А в узел В ведет дуга, если класс В является непосредственным наследником класса А. Этот граф изображает иерархию классов
с точки зрения наследования. Если наследование единичное, соответствующий класс является деревом (рис. 1). В корне дерева дерева находится прародитель - класс, для которого все остальные классы являются потомками.
 
 
 
             Множественное наследование описывается более общим ациклическим графом:
 
 
Производный класс расширяет свойства и поведение базового класса. В производном классе можно: Переопределение метода класса А в производном классе В, называемое также перегрузкой или перекрытием, - это определение в классе В метода с именем,
которое уже является именем некоторого метода в классе А. Обычно переопределение осуществляется для того, чтобы привести поведение объектов класса в соответствие
их изменившемуся состоянию.

5.2. Языки объектно-ориентированного программирования
Среди языков ООП в настоящее время наибольшее распространение  получил язык С++, который был создан Страуструпом в начале 80-х [1]. При создании С++ были решены две основные задачи: совместимость со стандартным С и расширение С конструкциями ООП, основанными на конструкциях типа классов из языка Simula 67. К моменту создания С++ язык С приобрел широкую популярность благодаря лаконичности и выразительности не только как язык системного программирования, но и как язык общего пользования. Поэтому конечная цель С++ - предоставление профессиональному программисту возможностей для создания объектно-ориентированного программного обеспечения без ущерба для эффективности и компактности С. Поскольку С++ основывается на С, он сохраняет большую часть этого языка, включая богатый набор операторов, выразительный стиль и расширяемость [2]. С++ - это союз между программированием на низком и высоком уровне. Пользователь может писать код на том уровне, который соответствует проблеме, сохраняя в то же время возможность реализации деталей на аппаратном уровне.
В отличие от Smalltalk, который является чисто объектно-ориентированным, С++ - гибридный язык. Понятие struct расширяется в С++ для того, чтобы позволить функциям быть её членами. Объявление функции включается в объявление структуры
и функция вызывается с использованием методов доступа к членам структуры. Структуры также могут иметь часть своих описаний private. Такое расширение struct привело к тому, что концепция class - это, фактически, struct с видимостью private
по умолчанию.
    В С++ при создании иерархии классов могут использоваться оба типа наследования: единичное и множественное. Чтобы сделать класс производным, в объявлении класса после имени и двоеточия надо указать список базовых классов, снабдив имя каждого базового класса спецификатором доступа public, protected или private. Например:
// Объявление производного класса В - наследника базового класса А
class B : public A
{
    // Здесь надо вставить объявление новых переменных,
    // новых и переопределяемых методов класса В
}
// Объявление класса HappyWoman - наследника классов
Happy и Woman class HappyWoman : public Woman, protected Happy
{
   // Здесь надо вставить объявление новых переменных,
    // новых и переопределяемых методов класса HappyWoman
}
Указываемые при объявлении производного класса спецификаторы доступа базовых классов служат для того, чтобы поставить дополнительную защиту доступа к наследуемым элементам базового класса по сравнению с уровнем защиты, предусмотренным базовым классом. Спецификатор public сохраняет уровень защиты наследуемых элементов базового класса. Protected ужесточает защиту: все наследуемые public-элементы базового класса получают статус protected. Private приписывает всем элементам этот статус.
Одной из важных особенностей в иерархии классов C++ является обеспечиваемая
лишь от родителей к потомкам совместимость по присваиванию: объекту родительского класса может быть присвоено значение объекта-потомка, обратное недопустимо. В частности, указателю базового класса может быть присвоен указатель на производный класс, что в сочетании с возможностью определения виртуальных методов обеспечивает механизм выбора среди методов базового и производных от него классов нужного метода динамически, т.е. на этапе выполнения программы, в отличие от обычных методов, обращение к которым формируется на этапе компиляции. Ключевое слово virtual - функциональный спецификатор, обеспечивающий такой механизм. Комбинация виртуальных функций и public-наследования представляет собой форму чистого полиморфизма и является наиболее общим и гибким способом формирования программного обеспечения.
Виртуальная функция является обычным выполняемым кодом. Семантика ее
вызова такая же, как и у других функций. В производном классе она, как правило, переопределяется, но, в отличие от переопределения обычных функций, в переопределяемых версиях виртуального метода должны сохраняться число параметров и их типы, а также тип возвращаемого значения, что гарантирует одинаковую форму вызова виртуального метода как базового, так и производного класса. Выбор того, какое определение вызвать для виртуальной функции, производится динамически. Типичный случай - когда базовый класс имеет виртуальные функции, а производные классы имеют свои версии этих функций. Указатель на базовый класс может указывать либо на объект базового класса, либо на объект производного класса. Выбранный метод зависит от класса, на объект которого указывается, но не от типа указателя. Таким образом, в схеме чистого полиморфизма решение о том, метод какого класса вызвать, принимается не на этапе компиляции, а на этапе выполнения программы. Этот механизм называется еще поздним связыванием. В качестве примера рассмотрим программу, в которой в определенный момент должна вычисляться суммарная площадь некоторых плоских фигур. Различные фигуры порождаются от базового класса shape.
Class shape
{
   protected:
         double x, y;
  public:
         virtual double area () { return 0; } // поведение по умолчанию
};
class rectangle : public shape
{
    private:
         double height, width;
    public:
         virtual double area () { return height*width; }
};
class circle : public shape
{
     private:
        double radius;
     public:
        virtual double area () { return PI*radius*radius; }
};
При такой иерархии система легко пополняется дальнейшим порождением классов. Вычисление площади является локальной ответственностью производного класса.
Код пользователя по полиморфному вычислению суммарной площади может выглядеть следующим образом:
shape* p[N];
.  . . .
double tot_area = 0.0;
for (int i=0; i < N; i++)
     tot_area += p[i]->area ();
Главное преимущество состоит в том, что этот код не нуждается в изменении,
даже если к системе добавляются новые фигуры. ООП с использованием С++
широко внедряется в индустрию программного обеспечения. Причина состоит
в том, что С++ приемлемым образом привносит технологию ООП. А именно, он основывается на существующем широко используемом удачном языке и позволяет писать компактный и эффективный код. Ключом ко всеобщему повороту к С++ стало понимание того, что наследование и полиморфизм дают важные преимущества над традиционной практикой программирования.
Среди других языков ООП отметим язык Java [8], который многими специалистами в первую очередь рассматривается как средство создания аплетов для World Wide Web. Термином аплет в Java обозначается мини-приложение, работающее внутри Web-страницы. После того как аплет загружен на компьютер пользователя, он может выполнять определенные задачи и взаимодействовать с пользователем через броузер, не требуя ресурсов Web-сервера. На самом деле Java является универсальным языком программирования, подходящим для создания самых разнообразных приложений. Язык Java использует многие конструкции языка С++, обладая в то же время существенными отличиями от последнего: Java - это чисто объектно-ориентированный язык, в нем допускается только единичное наследование и т.д.

5.3. Алгоритмическое и программное обеспечение обработки изображений
В стадии оформления.

5.4. Оконный пользовательский интерфейс

    Одним из недостатков операционной системы MS-DOS, которая стала фактическим стандартом для IBM PC-совместимых компьютеров в 80-е годы, был чрезвычайно примитивный пользовательский интерфейс. К тому времени на рынке уже появился компьютер Macintosh фирмы Apple c намного более
удобным оконным графическим пользовательским интерфейсом (Graphics User Interface, GUI), выглядевшем значительно выигрышнее командной строки IBM PC.
В оконном интерфейсе каждой выполняемой программе отводится экранное окно, которое может занимать часть экрана или весь экран.
    Фирма Microsoft, ведя самостоятельные разработки в области графического интерфейса пользователя, в 1990 г. выпустила графическую операционную
оболочку Windows 3.0, на смену которой вскоре пришла Windows 3.1. Главная
идея, заложенная в основу оболочки Windows, - естественность представления информации. Информация должна представляться в той форме, которая
обеспечивает наиболее эффективное восприятие её человеком. Windows характеризуется следующими особенностями [1]:

    С формальной точки зрения графическая оболочка Windows не была
операционной системой. Истинной 32-разрядной операционной системой
является Windows 95, в которой пользовательский интерфейс значительно
улучшен по сравнению с Windows 3.1 [2].
Система Windows 95 обеспечивает встроенную поддержку ряда объектов пользовательского интерфейса: окон, пиктограмм, меню, панелей
инструментов, строк состояния, блоков диалогов и т.п. Как уже упоминалось
выше, наиболее важным элементом пользовательского интерфейса Windows
является окно. С точки зрения пользователя окно обеспечивает наблюдаемость некоторого объекта данных на экране компьютера [3]. Однако этим дело не ограничивается, поскольку для пользователя окно отождествляется с самой
прикладной программой. Когда пользователь запускает прикладную программу,
он ожидает появления ее окна. Для завершения работы программы пользователь закрывает соответствующее окно. Для выбора конкретной программы он выбирает относящееся к ней окно. В число стандартных элементов окна входят заголовок
окна, кнопки максимизации (увеличения до размеров экрана) и минимизации (уменьшения до размеров пиктограммы) окна, область клиента, рамка окна,
а также полосы горизонтальной и вертикальной прокрутки (рис. 1).
 
 
Рис. 1

Windows 95 обеспечивает два типа оконного интерфейса пользователя: однодокументный (Single Document Interface - SDI) интерфейс и многодокументный (Multiple Document Interface - MDI) интерфейс. Если некоторое Windows-приложение реализует интерфейс SDI, то оно может создать только одно окно, в области клиента которого находится единственный объект обрабатываемых данных (документ). Наоборот, для Windows-приложения с интерфейсом MDI создается главное окно,
в области клиента которого могут создаваться дочерние окна, каждое из которых связано со своим индивидуальным объектом обрабатываемых данных (документом) (см. рис. 1).
Пиктограмма представляет собой небольшой рисунок, который служит для пользователя напоминанием о чем-либо. Системы на базе GUI построены на том принципе, что конкретное и видимое понятнее, чем абстрактное и невидимое [2]. Пиктограммы обеспечивают конкретный, видимый символ, обозначающий команду, программу или некоторые данные. Делая их видимыми на экране, программа для Windows делает их доступными. Обеспечив видимость на экране всех возможных
для выбора пользователем вариантов, программа уменьшает зависимость пользователя от его способности запоминать информацию.
 

 
Рис. 2

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


5.5. Программный комплекс для обработки аэрокосмических изображений
В стадии оформления.

Список литературы
1. Стефан Фойц. Windows 3.1 для пользователя. Торгово-издательское бюро BHV,
Киев, 1995.
2. К. Ахметов. Windows 95 для всех. Компьютер Пресс, Москва, 1977.
3. П. Нортон, П. Йао. Программирование на Borland C++ в среде Windows. “Диалектика , Киев, 1993, том 1.


АВТОРЫ*ОГЛАВЛЕНИЕ* ДОМ*ГЛАВА 1* ГЛАВА 2*ГЛАВА 3* ГЛАВА 4 * ГЛАВА 6* ГЛАВА 7
(C) 1998 Институт Вычислительной Математики и Математической
Геофизики СО РАН