Другие объектно-ориентированные системы программирования

 

Язык C++ является сейчас наиболее распространённым объектно-ориентированным языком. Однако существуют и другие популярные объектно-ориентированные языки и системы программирования. Здесь мы кратко рассмотрим языки Eiffel и Smalltalk.

Реализация классов

Определение класса Window на языке Eiffel мало отличается от соответствующего определения на языке C++:

class WINDOW

export

add_box, add_circle, clear_selections, cut_selections,

group_selections, move_selections,

redraw_all, select_item, ungroup_selections

feature

xmin, ymin, xmax, ymax: REAL;

Create (x0, y0, width, height: REAL) is body end;

add_box (x, y, width, height: REAL) is body end;

add_circle (x, y, radius: REAL) is body end;

add_to_selections (ashape: SHAPE) is body end;

clear_selections is body end;

cut_selections is body end;

group_selections: Group is body end;

move_selections (deltax, deltay: REAL) is body end;

redraw_all is body end;

select_item (x, y: REAL) is body end;

ungroup_selections is body end;

end -- class WINDOW

Все свойства (feature) класса (соответствуют членам класса в языке C++) считаются приватными, если только они не объявлены явно как общедоступные: все общедоступные свойства перечисляются в разделе export. Свойство Create (аналог конструктора класса в языке C++) всегда является общедоступным. Остальные особенности синтаксиса понятны и без пояснений.

Язык Smalltalk является языком интерпретируемого типа: программа в системе Smalltalk не компилируется, а переводится в интерпретируемое специальным интерпретатором внутреннее представление. Это позволило сделать систему Smalltalk интерактивной: программист имеет доступ к программе (может, например, изменять её) во время её интерпретации, что очень удобно при разработке и отладке программы, но, как известно, уменьшает её эффективность, так как интерпретация программы сопряжена с дополнительными накладными расходами.

Определение класса Window на языке Smalltalk имеет следующий вид:

class name Window

superclass Object

instance variables xmin, ymin, xmax, ymax: REAL

class methods

instantiating

createAt aPoint of Width: width ofHeigt: heigt

instance methods

adding shapes

addboxAt aPoint ofWidth: width ofHeigt: heigt

addCircleAt aPoint ofRadius: radius

refreshing window

redrawAll

manipulating selections

clearSelections

cutSelections

groupSelections

moveSelectionsBy: deltaPoint

selectItemAt: aPoint

ungroupSelections

private

addToSelections: aShape

Все классы языка Smalltalk являются подклассами системного класса Object, что позволяет использовать принадлежащие им по наследованию системные операции системы Smalltalk, определённые в классе Object. Строки в описании класса, выделенные курсивом, определяют категории методов. Они служат только для структурирования набора методов. Методы, включённые в категорию private, являются приватными и не доступны извне класса. Чтобы сделать атрибуты приватными, следует не определять методы для запроса и установки значений атрибутов. В системе Smalltalk определён системный метод @, который объединяет пару числовых значений в одно составное значение. Это позволило вместо двух переменных x и y (координат точки) использовать в нашем примере одну переменную aPoint, представляющую обе координаты точки (x,y). Операция присваивания значения (3,4) переменной aPoint с использованием метода @ имеет вид:

aPoint <- 3 @ 4

Порождение объектов

В языке Eiffel объявление переменной (в этом языке вместо термина «переменная» используется термин сущность (entity)) отделено от порождения соответствующего объекта. Объявление сущности определяет имя, значением которого может быть (объектная) ссылка на объект объявленного типа, но эта ссылка при объявлении получает неопределённое значение (void), т.е. не ссылается ни на какой объект. Пример объявления переменной:

w: WINDOW

В результате этого объявления создаётся переменная w, значением которой может быть ссылка на окно, но которая пока не ссылается ни на какое окно. Все объекты языка Eiffel – динамические: они создаются с помощью операции Create; например, следующий оператор создаёт окно с соответствующими параметрами и присваивает ссылку на него переменной w:

w.Create (0.0, 0.0, 8.5, 11.0)

В каждом классе неявно определена операция Create без параметров, которая создаёт новый объект этого класса с нулевыми значениями его атрибутов. Можно переопределить неявную операцию Create; например, для окон эту операцию можно определить следующим образом:

class WINDOW

...

feature

Create (x0, y0, width, height: REAL) is

do

xmin := x0; ymin := y0;

xmax := x0 + width; ymax := y0 + height;

end

...

end -- class WINDOW

Кроме операции Create, определена операция создания копий уже существующего объекта – Clone.

В языке Eiffel невозможно явным образом уничтожить объект (в нём отсутствует операция, подобная операции delete языка C++). Операция Forget убирает объектную ссылку из соответствующей сущности, но не уничтожает сам объект. Объект, на который нет ни одной объектной ссылки, уничтожается во время «чистки мусора», которая, если она не отключена программистом (для этого имеется специальная системная операция), выполняется автоматически.

Все объекты языка Smalltalk – динамические и размещаются в динамической памяти – куче. Удаление объектов осуществляется автоматически подсистемой чистки мусора. Все переменные не имеют типа и могут содержать объекты любого класса. Порождение объектов осуществляется операцией new, определённой в системном классе Object (все классы языка Smalltalk – наследники класса Object). Например, порождение окна со стандартными параметрами (определяемыми по умолчанию) осуществляется операцией:

w <- Window new

Операция new является одним из методов уровня класса. С её помощью можно определить ещё один метод порождения окна (уже с параметрами):

w <- Window createAt: 0 @ 0 ofWidth: 8.5 ofHeight: 11.0

Этот метод может быть определён следующим образом:

class name Window

...

class methods

createAt: aPoint ofWidth: width ofHeigt: heigt

| w |

w <- self new.

w initialize: aPoint ofWidth: width ofHeigt: heigt.

instance methods

initialize: aPoint ofWidth: width ofHeigt: heigt.

xmin <- aPoint x.

ymin <- aPoint y.

xmax <- xmin + width.

ymax <- ymin + height

Отметим, что метод уровня класса не имеет непосредственного доступа к атрибутам объектов. Поэтому для инициализации окна потребовалось определить метод уровня объекта initialize

 

Вызов операций

В языке Eiffel методы называются подпрограммами (routines). При вызове этих подпрограмм им передаются параметры, которые могут иметь простой тип (REAL, INTEGER, BOOLEAN, или CHARACTER) или быть объектами классов, определенных программистом. В подпрограмме не разрешается изменять значения формальных параметров путём присваивания им новых значений или применения к ним операции (такие как Create, Clone или Forget), которые могут менять значение объектной ссылки. В то же время остальные операции могут быть применены к объектам, являющимся формальными параметрами, что вызовет изменение состояния указанных объектов.

Синтаксис вызова операции в языке Eiffel такой же, как в языке C++, причём операция '.' языка Eiffel соответствует операции '->' языка C++:

local

aShape: SHAPE;

dx, dy: REAL

do

...

aShape.move (dx, dy);

end

В языке Eiffel определён неявный доступ к свойствам целевого объекта по имени соответствующего свойства. Идентификаторы x и y являются именами атрибутов целевого объекта SHAPE:

move (deltax, deltay: REAL) is

-- move a shape by delta

do

x = x + deltax;

y = y + deltay

end

В языке Eiffel имеется предопределённый идентификатор Current, который именует целевой объект операции (он аналогичен идентификаторам this языка C++ и self языка Smalltalk). Поэтому предыдущий фрагмент программы можно записать следующим эквивалентным образом:

move (deltax, deltay: REAL) is

-- move a shape by delta

do

Current.x = Current.x + deltax;

Current.y = Current.y + deltay

end

В языке Smalltalk все параметры и переменные являются объектами; все операции являются методами, связанными с этими объектами. Применить операцию к объекту – значит послать этому объекту сообщение, состоящее из имени операции и списка значений её параметров. Сообщение связывается с объектом во время выполнения программы (динамически), рассматривается класс соответствующего объекта и находится соответствующая операция в этом классе или в его предках (по наследованию). Формальные параметры метода запрещено изменять внутри метода с помощью присваиваний. Синтаксис обращения к операции (посылки сообщения) следующий:

aShape moveDelta: aPoint

Этот метод можно реализовать следующим образом:

class name Shape

instance variables

x y

instance methods

moveDelta: aPoint

x <- x + aPoint x

y <- y + aPoint y

Внутри метода разрешён непосредственный доступ по имени к атрибутам целевого объекта операции (в языке Smalltalk атрибуты называются переменными объекта (instance variables)).

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

 

Реализация наследования

В языке Eiffel список наследования помещается вслед за ключевым словом inherit:

class ITEM

export

cut, move, pick, ungroup

feature

cut is deferred end;

move (deltax, deltay: REAL) is deferred end;

pick (x, y: REAL): BOOLEAN is deferred end;

ungroup () is deferred end

class SHAPE

export

cut, draw, erase, move, pick, ungroup, write

inherit ITEM

feature

* x, y: REAL;

cut is <body> end;

draw is <body> end;

erase is <body> end;

move (deltax, deltay: REAL) is <body> end;

pick (x, y: REAL): BOOLEAN is <body> end;

ungroup is <body> end;

write (acolor: COLOR) is deferred end;

end

classrBOX

export pick, write

inherit SHAPE redefine pick, write

feature

width, height: REAL;

Create (x0, y0, width0, height0:*REAL) is <body> end;

pick (x, y: REAL): BOOLEAN is <body> end;

write (acolor: COLOR) is <body> end

end

class CIRCLE

export pick, write

inherit SHAPE redefine pick, write

feature

radius: REAL;

Create (x0, y0, radius0: REAL) is <body> end;

pick (x, y: REAL): BOOLEAN is <body> end;

write (acolor: COLOR) is <body> end

end

Для обозначения абстрактных операций используется ключевое слово deferred; такие операции должны быть реализованы во всех подклассах. Переопределение свойств класса в подклассе отмечается в разделе redefine.

В языке Smalltalk описание класса Item, его подкласса Shape, а также подклассов Box и Circle класса Shape может иметь следующий вид:

class name Item

superclass Object

class name Shape

superclass Item

instance variables

x

y

instance methods

cut

draw

erase

move: aPoint

ungroup

class name Box

superclass Shape

instance variables

width

height

instance methods

pick: aPoint

write: aColor

class methods

createAt: aPoint width: widthSize length: lengthSize

class name Circle

superclass Shape

instance variables

radius

instance methods

pick: aPoint

write: aColor

class methods

createAt: aPoint radius: radiusSize

Все атрибуты суперкласса доступны всем его потомкам. Все методы могут быть переопределены в подклассах. Множественное наследование не поддерживается.

Реализация зависимостей

В языке Eiffel для реализации зависимостей применяются конструкции, аналогичные соответствующим конструкциям языка C++. Поддерживаются параметризованные (родовые (generic)) контейнерные объекты (обычно эти объекты параметризуются относительно типов объектов, которые они содержат). Базовая библиотека классов системы Eiffel содержит контейнерный класс LINKED_LIST, который можно использовать для реализации зависимости типа «много к одному» между классами ITEM и GROUP:

class ITEM

export

get_group

-- выборочный экспорт в класс GROUP

set_group(GROUP), forget_group(GROUP)

feature

get_group: GROUP is

do

Result := mygroup

end;

set_group(g:GROUP) is

do

mygroup := g

end;

forget_group is

do

forget(mygroup)

end;

end --ITEM

class GROUP

export

add_item, remove_item, get_items

inherit ITEM

feature

items: LINKED_LIST[ITEM]; --параметризованный тип

Create is

do

items.Create

end;

add_item(value:ITEM) is

do

items.finish;

items.insert_right(value);

value.set_group(Current)

end;

remove_item(value:ITEM) is

do

items.search(value,l);

items.delete;

value.forget_group

end;

get_items(number:INTEGER):ITEM is

do

Result := items

end;

end --GROUP

Язык Eiffel обеспечивает выборочный экспорт относительно любого свойства. В рассматриваемом примере в класс GROUP экспортируются свойства set_group и forget_group класса ITEM. Это поддерживает инкапсуляцию путём ограничения доступа по записи данных в объекты классов, участвующих в зависимости между ITEM и GROUP.

Операция forget языка Eiffel предназначена для освобождения памяти; она освобождает память, занимаемую объектом, который является её операндом, а также присваивает объектной ссылке неопределённое значение.

В языке Smalltalk большую часть зависимостей помогает реализовать богатая системная библиотека классов. Например, для реализации зависимости типа «много к одному» между графическими объектами (Item) и группой, в которую они входят (Group), можно использовать библиотечный класс Set:

class name Item

superclass Object

class name Shape

superclass Item

instance variables

group

instance methods

cut

draw

erase

move: aPoint

ungroup

--дополнительные методы

getGroup

group

--приватные методы

putGroup: aGroup

group <- aGroup

class name Group

superclass Item

instance variables

items

class methods

new

|((super new)putItems:(Set new))

instance methods

pick: aPoint

write: aColor

addItem: anItem

items add: anItem.

anItem putGroup: self

removeItem

items remove: anItem.

anItem putGroup: nil

getItems

|items copy

--приватные методы

putItems: aSet

items <- aSet

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