Объектно-ориентированные среды

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

Основные понятия

Объектно-ориентированное программирование (сокращенно ООП) и порож­денное им объектно-ориентированное проектирование – это совершенно новый подход к построению сложных (и не очень сложных) программ и систем. Этот под­ход зародился в таких языках программирования, как Ада, Smalltalk, C++, Bor­land Pascal. До появления ООП господствовало процедурное программирование. Тогда основой программ были функции и процедуры, т.е. действия. Разработчик определял, какие действия, какие функции нужны ему для решения поставленной задачи, реализовывал эти функции и объединял их в программу. Программа обыч­но имела достаточно четкий алгоритм работы – последовательность операций, на­чинающуюся в какой-то точке и заканчивающуюся в одной или множестве других точек.

В объектно-ориентированном программировании и проектировании главной, отправной точкой является не процедура, не действие, а объект. Такой подход представляется достаточно естественным, поскольку в реальном мире мы имеем дело именно с объектами (людьми, предметами, техническими устройствами), взаимодействующими друг с другом. Да и взаимодействие пользо­вателя с компьютерной программой – это тоже взаимодействие двух объектов – программы и человека, которые обмениваются друг с другом определенными сооб­щениями.

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

поддается хранению и обработке;

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

Прикладная программа, построенная по принципам объектной ориентации – это не последовательность каких-то операторов, не некий жесткий алгоритм. Объектно-ориентрованная программа – это со­вокупность объектов и способов их взаимодействия. Отдельным (и главным) объ­ектом при таком подходе во многих случаях можно считать пользователя програм­мы (рис. 3.1). Обмен между объектами происходит посредством сообщений. Сообщение является совокупность данных определенного типа, передаваемых объектом-отправителем объекту-получателю, имя которого указывается в сообщении. Получатель реагирует на сообщение выполнением каких-либо действий, или никак не реагирует на него.

 

 

Рекурсия

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

Пример. Рекурсивное определение натурального числа:

1) 1 – натуральное число;

2) число, которое на 1 больше натурального числа, также натуральное.

В системах логического программирования рекурсия служит также для описания циклов, повторений и является важнейшим методом программирования.

Рассмотрим простой пример: вычисление факториала натурального числа n (n!). Определение n! рекурсивно:

1) 1! = 1,

2) n! = (n–1) ! * n

Для описания отношения “факториал” между n и n! будем использовать двухар­ный предикат

 

факт(N,М).

 

Тогда база знаний, соединенная с запросом, приобретает вид:

 

факт(1,1).

факт(N,Х) : - факт( N–1 ,Y), X is Y*N.

?- факт(3,A);

 

В данной программе правило “факт” вызывает само себя – это и есть рекурсия. Запись is Y*N представляет собой обращение к встроенному предикату “is” (“есть”) для описания арифметического действия.

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

 

?факт(3,А0).

ОТВЕТ : А=6

?факт(2,А1).

X1= 2*3 = 6

?факт(1,А2).

Х2= 1*2 = 2

факт(1,1).

 

Правило “факт” вызывает само себя – происходит углубление рекурсии (прямой ход). При этом в памяти ЭВМ выделяется место для переменных А,А0,А1,А2 и N,N0,N1,N2, образующих стеки. При согласовании вопроса с предикатом факт(1,1) рекурсия прекращается и начинается возврат из рекурсии (обратный ход) – выпол­нение отложенных на прямом ходе согласований. Предикат факт(1,1) играет очень важную роль – это ограничитель рекурсии, условие ее завершения.

Отметим, что Пролог стремится найти все решения поставленной задачи, а зна­чит, после появления ответа А=6 происходит возврат к вопросу ?факт(1,А2) и попытке согласовать его с правилом “факт”. Это приводит к бесконечному процес­су рекурсии с отрицательными аргументами в “факт”, которая завершается при исчерпании глубины зарезервированных интерпретатором Пролога стеков. Уско­рить выход из рекурсии можно, добавив к предикату “факт(1,1)” отсечение !:

 

факт(1,1) : - !.

 

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

В общем случае последовательность предложений в базе знаний не имеет значе­ния. Однако это не так для рекурсивно-определенных отношений. Например:

 

родитель(X):- родитель(Y), отец(Y,Z).

 

родитель(коля).

отец(коля,петя).

родитель (петя).

 

В этом случае в первом предложении голова имеет ту же функцию, что и одна из целей – “родитель”. В процессе поиска ответа в этой базе знаний будет применено правило: предложение, стоящее первым, будет применено первым – известное как принцип поиска в глубину.

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

 

родитель(коля).

родитель(X):- родитель(Y), отец(Y,Х).

отец(коля,петя).

? - родитель(петя).

 

Неограничено-повторное обращение к предложению может быть и более замас­кированным так, как это получается в следующей программе:

 

выше (А, В): - ниже (В, А).

ниже(В,А): - выше(А,В).

выше(коля,петя).

?- ниже(петя,коля).

 

Однако если третье предложение стоит на первом месте, то повторного обраще­ния не произойдет и ответ будет найден.

В общем виде рекурсия на Прологе выглядит так:

 

Р(1,...).

Р(n,...) :- Q1, ..., Qn, P(n–1,…), R1, ... Rm.

 

Правило Р обращается само к себе, при этом происходит углубление рекурсии. Предикаты Q1, ..., Qn выполняются на прямом ходе рекурсии, а R1,..., Rm – на обратном; n – это некоторый условный параметр, входящий в условие продолжения рекурсии, а Р(1,...) – факт, завершающий процесс рекурсии.

Особенно простым случаем рекурсии является простое циклическое повторение. Один из способов организации повторения связан с наличием в базе знаний проце­дуры вида repeat.repeat:-repeat.

Использование repeat в качестве подцели некоторого правила приводит к мно­гократному повторению остальных подцелей этого правила.