Конспект установочных лекций по комплексному курсу Информатика, Теория информации

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


Объектная ориентированность пытается претворить в жизнь общие принципы разработки программного обеспечения и программ с помощью учета конкретных способов разработки и использования вполне определенных средств описания. Исторически объектная ориентированность восходит к языкам программирования Simula-67 и Smalltalk. В настоящее время одним из наиболее употребительных на практике языков этого типа является C++.

Для обычных фаз разработки программ характерны следующие моменты объектной ориентированности:

·         объектно-ориентированный анализ,

·         объектно-ориентированный проект,

·         объектно-ориентированное программирование.

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

При 00-программировании опираются на следующие концепции:

·         инкапсуляция данных,

·         классы и наследование,

·         объекты и воплощение (динамическое создание новых объектов),

·         вызов методов и обмен сообщениями.

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

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




·         модульность,

·         унификация и систематика,

·         модифицируемость и гибкость,

·         повторная применимость (переносимость).

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

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

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

Можно различать следующие два основных направления 00-программирования:

(а) объектная ориентированность в традициях программной инженерии (как она выступает, например, у Б. Майера или реализуется в языках Smalltalk, Eiffel, а также в вариантах языка С),

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



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

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

В подходах к объектной ориентированности существуют заметные различия в моделях протекания процесса вычислений:

·         последовательное выполнение (как в Simula, C++, Eiffel, Smalltalk),

·         параллельное выполнение (00-SDL, GRAPES).

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

Центральными понятиями для объектной ориентированности являются классы

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

и часто каналов коммуникаций. Таким образом, класс представляет собой совокупность:

·         типов (типы данных),

·         функций, процедур (или методов),

·         переменных (или атрибутов),

·         каналов коммуникаций,



·         других классов (при определенных обстоятельствах).

Класс имеет обозначение, которое используется (также как тип) для объявления объектов этого класса.

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

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

Под термином объектная ориентированность между тем охватываются хорошо известные принципы software-инженерии. При этом в основе лежит принцип модульности,

который подразумевает известные критерии software-систем:

·         модульную декомпозицию (модульная разложимость системы на под системы),

·         модульную композицию (модульная собираемость системы из подсистем),

·         модульную понимаемость (независимая понимаемость подсистемы),

·         модульную стабильность (модульная модифицируемость, локальность изменений),

·         модульную инкапсуляцию (модульная защита, однозначно установленные права и методы доступа).

Модульность требует особенно тщательной спецификации и описания взаимодействия (интерфейса) между составными частями software-системы. Поэтому формульная спецификация поведения интерфейса представляет особый интерес.

Для образования интерфейса выдвигаются следующие пять принципов, которые сохраняют свою силу и вне объектной ориентации:

·         синтаксически ясная и независимая формулируемость единиц (частей системы),



·         небольшое число точек разреза (интерфейсов) (адекватная гранулированность проекта системы),

·         простота интерфейса ( простота точек разреза, их адекватный выбор),

·         явное описание интерфейса,

·         упрятывание информации о реализации (принцип инкапсуляции).

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

·        схема объявлений типов,

·        схема родственных вычислительных структур (типы и алгоритмы),

·        схема для вычислительных предписаний.

На переднем плане стоит осознание структурных и поведенческих общностей с целью:

·        независимость представления (упрятывание информации),

·        использование общностей родственных единиц.

Многократное использование поддерживается следующими концепциями:

·        перезафузки (англ. overloading) операторов,

·        наследования,

·        полиморфизма,

·        инкапсулированных, параметризуемых, генерируемых структур.

В объектной ориентированности присутствует как параметрический полиморфизм, так и ad-hoc-полиморфизм (перекрытие).

В параметрическом полиморфизме используются те же самые тела функций и, соответственно, процедур, которые работают с объектами различных типов. В ad-hoc-полиморфизме

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


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

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

Существенными, техническими составными частями объектной ориентированности являются:

·         концепция классов с отношениями наследования и быть частью (иерархия классов, отношение "является частью"),

·         концепция коммуникации и устойчивость программных переменных (см. ниже),

·         динамическое создание (воплощение) и удаление объектов.

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

Отношение наследования "класс А есть один из классов В" выражает, что объект класса А является также и объектом класса В. Это значит, что класс А обладает всеми составными частями и свойствами (всеми атрибутами и методами), которые имеет класс В, и в данном случае еще некоторыми дополнительными. Класс А наследует составные части класса В. При наследовании делается различие между

·         единственным и

·         множественным

наследованием.


При единственном наследовании один класс наследует свойства самое большее от одного из классов. При множественном наследовании один класс наследует свойства от нескольких других классов.

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

Далее даются простые примеры классов и 00-концепций, чтобы разъяснить эти понятия.

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

spec QUEUE =

import POOL,

sort bool, data, queue data,

subsort queue data inherits from set data,

fct deq ==  ( queue data ) queue data,

fct next = ( queue data ) data Axioms:

deq(add(empty, e)) = empty,

next(add(empty, e)) = e,

deq(add(add(q, d), e)) = add(deq(add(q, d)), e),       ~

next(add(add(q, d), e) = next(add(q, d)) end_of_spec spec QUEUE 1 =

sort bool, data, queuel data,

subsort queuel data inherits from queue data Axioms:

any(s) = next(s) end_pf_spec

Переменная v типа var queue data может принимать значения типа queue data или типа queuel data. Тем самым результат вызова any(v) будет зависеть от типа переменной v. Если значение v имеет тип

queuel data,
то вызов any(v) соответствует вызову next(v), в противном случае - нет. Тогда говорится о полиморфизме

и о динамическом связывании

(англ. late binding).

Как правило, объекты имеют состояния, которые определяются значениями их атрибутов. Это ведет к понятию устойчивости,

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

Атрибуты в качестве значений могут содержать также ссылки на объекты. Это определяет структуру связей между объектами.

Операционно можно смоделировать устойчивость посредством спецификации большого глобального пространства состояний, в котором состояния отдельных объектов содержатся как частичные состояния.


Каждый метод может изменять соответствующую часть.

Инкапсуляция программных переменных в объекты с помощью атрибутов ведет, строго говоря, только к специальным правилам видимости для программных переменных.

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

·         автоматов ввода/вывода,

·         потокообрабатывающих функций,

В частности, объект можно понимать как машину состояний с входом и выходом.

Пример (описание классов для объектов с устойчивостью данных). Типичный для 00-программирования пример класса выглядит следующим образом:

class SET_CLASS = based on:            SET Attributes:          s : set data Methods:           put_empty,

              padd      param data,

                    pdelete    param data Selektors:            sisempty:   -> bool,

                    siselem:    data -> bool,

                    sany:      -> data Axioms:             put_empty = [ s := empty ],

padd(x) = [ s := add(s, x) ],

pdelete(x) s [ s := delete(s, x) ],

siselem(x) = iselem(s, x),

sisempty = isempty(s),

sany = any(s) end_of_class

Здесь речь идет о классе 00-языка программирования с последовательной моделью выполнения.

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

Пример (описание класса интерактивного объекта). Типичным для 00-программирования примером является следующее описание класса:

class INTERACTIVE_SET_CLASS = Based on:     SET State:        set data Input Channel Messages:



message,

data -> message,

data ->• message,

message,

data -> message,

message,

put_empty:

padd:

pdelete:

sisempty:

siselem:

sany:

data bool

Output Channel Messages:

message, message,

data:

bool:

Axioms:

(см. табл.11.1) end_of_class

Поведение объекта класса задано таблицей переходов состояний. Здесь речь идет о примере класса 00-языка программирования с параллельной моделью

выполнения.

 

                       Таблица 11.1. Таблица переходов состояний для класса

Ввод

Состояние ввода

Вывод

Следующее состояние

Putempty

S

Empty

Padd(d)

S

add(s, d)

Pdelcte(d)

S

delete(s, d)

Sisempty

S

bool(isempty(s))

S

Siselem(d)

S

bool(iselem(s))

S

Sany

S

data(any(s))

S

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

Формализация этого обращения с классами и объектами возможна с помощью явного представления ссылок и создания объектов. Это ведет к понятию состояния по аналогии с состоянием памяти

Пример (классы с созданием объектов). Приведем типичный пример класса с созданием объекта:

class QUEUE_CLASS = Based on: QUEUE

Attributes: d : data, b : bool, s : Pointer to QUEUE_CLASS,

Methods:   put_empty,

padd    param data, pdeq

Selectors:   qisempty: -> bool, qnext:    -»data

Axioms:    put_empty = [b := true ],

padd(x) = [if b      then       d := x;

b := false;

create(s);

s.put_empty(s) else       s.padd(x) fi], pdeq =   [if qisempty(s)  then    b :== true

else    d :== qnext(s); s.pdeq(s) fi], qisempty = b, qnext = d

end_of_class

Концепция наследования касается таких составных частей класса, как:



·         атрибуты (компоненты состояния),

·         методы (функции и процедуры)

как имена (ad-hoc-полиморфизм), как предписания (параметрический полиморфизм),

·         свойства поведения.

Дополнительные отношения на классах и объектах, которые часто имеют место в 00-описаниях, это:

·         является (чем-либо),

·         знает, использует, клиент,

·         является частью (чего-либо).

Эти отношения выражают определенные связи между объектами некоторого класса. Для разработки систем и software представляет интерес формализация этих отношений.

00-программирование является, несомненно, одним из наиболее интересных направлений для профессиональной разработки программ. Впрочем, здесь имеются еще нерешенные проблемы:

·         интерфейс часто бывает недостаточно описан;

·         в проектировании software концепция воплощения трудно осваивается и просматривается;

·         нахождение классов часто бывает трудным и требует больших затрат;

·         отсутствуют формальные модели;

·         концепция модульности для программирования по большому счету недостаточна (классы для этого слишком мелки); связь с обычной software-инженерией зачастую описана неясно (E/R-моделирование, переход от последовательной модели выполнения программ к параллельной).

Тем не менее, от объектной ориентированности ожидаются большие выгоды в отношении снижения стоимости, повышения качества и повторной применимости software.


Содержание раздела