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

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

Процедуры

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

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

Пример: стек

Чтобы проиллюстрировать эти проблемы, рассмотрим ситуацию, когда программисту нужно реализовать управление простым стеком. Следуя старым добрым принципам разработки программного обеспечения, наш программист прежде всего определяет внешний интерфейс— скажем, набор из четырех процеду рinit, push, pop иtop. Затем он выбирает подходящий метод реализации. Здесь есть из чего выбрать: массив с указателем на вершину стека, связный список и т. д. Наш бесстрашный разработчик выбирает один из методов, а затем приступает к кодированию, как показано в листинге1.1.

Легко увидеть, что данные, образующие стек, не могут быть сделаны локальными для какой-то из четырех процедур, поскольку эти данные являются общими для всех из них. Но если у нас есть только локальные или глобальные переменные(как это имеет место для Fortran или было вC, до того как ввели модификато рstatic), то данные стека должны содержаться в глобальных переменных. Однако если переменные являются глобальными, то нет способа ограничить доступ к ним или их видимость. Например, если стек реализован как массив с именем datastack, то об этом должны знать все остальные программисты, поскольку они могут захотеть создать переменные с таким же именем, чего делать ни в коем случае нельзя. Запрет на использование имени datastack необходим,

даже если сами данные важны только для подпрограмм работы со стеком и не будут использоваться за пределами этих четырех процедур. Аналогично имена init, push, pop и top являются теперь зарезервированными и не должны встречаться в других частях программы(разве что с целью вызова процедур), даже если эти части не имеют ничего общего с подпрограммами, обслуживающими стек.

 

Листинг 1.1. Процедуры не годятся для маскировки информации

int datastack[100]; int datatop = 0; void init()

{

datatop = 0;

}

void push(int val)

{if (datatop < 100)

datastack [datatop++] = val;

}

int top()

{

if (datatop > 0)

return datastack [datatop — 1]; return 0;

}

int pop()

{

if (datatop > 0)

return datastack [—datatop];return 0;

}

Область видимости для блоков

Механизм видимости для блоков, использованный в языке Алгол и его преемниках(таких, какPascal), предлагает чуть больший контроль над видимостью имен, чем просто различие между локальными и глобальными именами. Кажется, мы могли бы надеяться, что это решит проблему скрытия информации. К сожалению, проблема остается. В любой области, в которой разрешен доступ к именам четырех процедур, видны также и их общие данные. Чтобы решить эту дилемму, требуется разработать иной механизм структурирования.

begin var

datastack : array [1..100] of integer; datatop : integer;

procedure init; . . .

procedure push(val : integer); . . .

function pop : integer; . . .

. . .

end;

Модули

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

 

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

Дэвид Парнас [Parnas 1972] популяризовал понятие модулей. Он сформулировал следующие два принципа их правильного использования:

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