Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
OOP(3S)X.DOC
Скачиваний:
1
Добавлен:
14.08.2019
Размер:
184.32 Кб
Скачать

Еще раз подведем итоги.

  • Как демонстрирует программа Farrej - инструментарий, предоставляемый модулем L1List, позволяет программировать работу с однонаправленными линейными списками, не умея пользоваться данными типа ссылка (и даже не зная их). Достаточно знать лишь семантику средств, объявленных в интерфейсной секции модуля (которая описана там, к сожалению, не на языке спецификаций, а просто в комментариях). Однако этого эффекта в определенной мере можно было бы достичь и ограничившись средствами аппарата процедур-функций.

  • Модуль вводят в употребление новые средства программирования - механизм инкапсуляции. Инкапсуляция (encapsulation)– «скрытие», защита от внешнего воздействия: из вне модуля доступны данные и операции, определенные в модуле (локальные???!!!), но только те, которые объявлены в интерфейсной секции (как видимые). Понятие инкапсуляция вносит существенно новое в дилемму локальные - глобальные объекты.

  • Интерфейсные объекты - описанные в интерфейсной секции:

  • интерфейсный тип данных – TVal (в модуле UGlob);

  • интерфейсная переменная – CurVal;

  • интерфейсные процедуры и функции - ResetList , GetNext , InsPred, WriteAll, EOList, ExistNext.

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

  • Инкапсулированные объекты - описанные в секции реализации:

  • инкапсулированные типы данных – TPElem, TElem;

  • инкапсулированные переменные - PFirst,PCur, PPred;

  • реализация тел интерфейсных процедур и функций – тоже инкапсулирована.

Инкапсулированные объекты «скрыты в капсуле», вне модуля на них невозможно ссылаться по их именам. Однако, не являясь глобальными, они не являются и локальными объектами модуля. Из смысла программы Farrej ясно, что инкапсулированные в модуле L1List переменные PFirst,PCur,PPred «живут» в течении всего периода выполнения программы Farrej. Они «непрерывно хранят» положение 1-го, текущего и ему предшествующего элементов списка, и изменяются в процессе работы программы со списком. Манипулировать списком и, в частности этими переменными, программа Farrej может только неявно с помощью («рук-манипуляторов») ResetList, GetNext, InsPred.

Кстати, традиционной локальной переменной является p:TPElem (точнее, их две – в процедурах InsPred и WriteAll).

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

Надо со всей определенностью отметить – приведенный в примере модуль L1List нельзя назвать описанием абстрактного типа данных «Линейный однонаправленный список». Модуль L1List позволяет работать с любым, но только с одним экземпляром типа «Линейный однонаправленный список». Чтобы воспользоваться инструментарием этого модуля для решения задачи «Разбить список на два по заданному критерию», придется продублировать модуль L1List три раза (под разными именами).

Модуль L1List вообще не является описанием какого либо типа данных, скорее он является описанием некоторого информационного и операционального ресурса, позволяющего работать с одним экземпляром типа «Линейный однонаправленный список».

Устранить отмеченный недостаток нетрудно, надо:

  • избавиться от нелокальных переменных в модуле;

  • определить в модуле подходящую структуру данных (тип данных, а не переменную), в которой можно было бы хранить все, что требуется о списке;

  • и «параметризовать» модуль, объявив во всех его процедурах и функциях формальный параметр – с каким списком выполняется работа.

Нижеприведенная программа соответствующим образом устраняет отмеченные недостатки, но!?…

  • Пришлось в интерфейсную секцию вынести определение типа TL1List – оно не нужно программе Farrej (и другим подобным программам), но имя этого типа данных нужно!

  • TL1List «потянул за собой» TPElem и TElem.

  • Теперь программа Farrej имеет открытый доступ к «внутренности» переменной RFarrej, а через нее по ссылкам ко всей внутренней структуре данных модуля TL1List, - модуль не защищен от внешнего вмешательства в функционирование его инструментов (*).

  • Теперь неясно, как «объехать» возникшие нежелательные последствия «улучшений» - чего-то не хватает в средствах описания модуля?

PROGRAM\OOP\FARREJ.002\FARREJ.DPR

{Файл UGlob.PAS}

UNIT UGlob;

INTERFACE

TYPE TVal=RECORD Ch,Zn:INTEGER END;

CONST C00:TVal=(Ch:0;Zn:0); { В Object Pascal 2 таким способом }

{ можно определять именованные константы структурных типов }

IMPLEMENTATION

END.

{Файл L1List.PAS}

UNIT L1List;

INTERFACE

USES UGlob;

TYPE TPElem=^TElem; TElem=RECORD Inf:UGlob.TVal; Next:TPElem END;

TL1List=RECORD PFirst,PCur,PPred:TPElem END { это и есть

структура данных, в которой можно хранить все, что

требуется знать о состоянии списка };

PROCEDURE ResetList(VAR List:TL1List);

FUNCTION EOList(List:TL1List): BOOLEAN;

FUNCTION ExistNext(List:TL1List): BOOLEAN;

PROCEDURE GetNext(VAR List:TL1List);

PROCEDURE InsPred(VAR List:TL1List;ValEl:UGlob.TVal);

PROCEDURE WriteAll(List:TL1List;VAR TxtF:TextFile);

PROCEDURE InitList(VAR List:TL1List); {процедура инициализации }

{ списка List – делает его пустым }

FUNCTION FCurVal(List:TL1List):UGlob.TVal; {функция извлечения }

{ значения (числитель и знаменатель) текущего элемента. }

{ В Object Pascal 2 функция может иметь значение }

{ «почти» любого типа }

IMPLEMENTATION

PROCEDURE ResetList; BEGIN List.PPred:=NIL; List.PCur:=List.PFirst;

END;

FUNCTION EOList; BEGIN EOList:=(List.PCur=NIL) END;

FUNCTION ExistNext;

BEGIN ExistNext:=(List.PCur<>NIL)AND(List.PCur^.Next<>NIL) END;

PROCEDURE GetNext; BEGIN

IF List.PCur<>NIL THEN BEGIN List.PPred:=List.PCur;

List.PCur:=List.PCur^.Next;

END

END;

PROCEDURE InsPred; VAR p:TPElem; BEGIN

NEW(p); p^.Inf:=ValEl; p^.Next:=List.PCur;

IF List.PPred=NIL THEN List.PFirst:=p

ELSE List.PPred^.Next:=p; List.PPred:=p

END;

PROCEDURE WriteAll; VAR p:TPElem; BEGIN p:=List.PFirst;

WHILE p<>NIL DO BEGIN

WRITE(TxtF,p^.Inf.Ch,':',p^.Inf.Zn,';'); p:=p^.Next

END; WRITELN(TxtF)

END;

PROCEDURE InitList; BEGIN

List.PFirst:=NIL;List.PCur:=NIL;List.PPred:=NIL;

END;

FUNCTION FCurVal; BEGIN

IF List.PCur<>NIL

THEN FCurVal:=List.PCur^.Inf ELSE FCurVal:=UGlob.C00

END;

INITIALIZATION

FINALIZATION

END.

{Файл Farrej.DPR}

{$B-,D+,I+,Q+,R+}

PROGRAM Farrej;

USES SysUtils,UGlob,L1List;

VAR RFarrej:TL1List; PredCur,x:UGlob.TVal; FIn,FOut:TextFile;

i,n:INTEGER;

BEGIN L1List.InitList(RFarrej);

x.Ch:=0;x.Zn:=1;L1List.InsPred(RFarrej,x);

x.Ch:=1;{x.Zn:=1;}L1List.InsPred(RFarrej,x);

AssignFile(FIn,'FIn.TXT'); RESET(FIn); READ(FIn,n); CloseFile(FIn);

AssignFile(FOut,'FOut.TXT'); REWRITE(FOut); WRITELN(FOut,n);

FOR i:=2 TO n DO BEGIN

L1List.WriteAll(RFarrej,FOut);

L1List.ResetList(RFarrej);

REPEAT PredCur:=L1List.FCurVal(RFarrej);

L1List.GetNext(RFarrej);

x:=L1List.FCurVal(RFarrej);

IF (PredCur.Zn+x.Zn)=i THEN BEGIN

x.Ch:=PredCur.Ch+x.Ch; x.Zn:=i;

L1List.InsPred(RFarrej,x)

END

UNTIL NOT L1List.ExistNext(RFarrej);

END; L1List.WriteAll(RFarrej,FOut); CloseFile(FOut)

END.

  1. ОБЪЕКТНО-ОРИЕНТИРОВАННЫЕ СРЕДСТВА ПРОГРАММИРОВАНИЯ.

На развитие языков программирования очевидное влияние оказывают три фактора.

  • Расширение сферы применения программных систем.

Начиналось все с задач сугубо вычислительного характера. Расширение на задачи экономического характера привело к развитию средств группировки данных. Сегодня сфера применения программных систем охватывает почти все…

  • Возрастание сложности программных систем и длительности их жизненного цикла. А это означает - возрастание трудоемкости их разработки и сложности управления процессом проектирования-разработки-эксплуатации программных систем.

Становление технологий структурного проектирования в 70-х годах привело к развитию средств группировки действий и процессов в языках программирования.

  • Языки программирования и программы – математические объекты, естественно они являются объектами математических исследований, а процессы проектирования-разработки-эксплуатации программных систем являются объектами системно-методологических исследований.

Благодаря этим исследованиям происходит отсечение «не очень нужного», замыкание «очень нужного» и упорядочение получившегося в итоге инструментария. Эти исследования создают теоретическую базу для сохранения прагматичной концептуальной целостности языков программирования (*).

Видимо, именно глобализация сферы применения программных систем смещает акценты – от понятия «инструменты программирования» к понятию «предметная область», к которой эти инструменты применяются.

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

ОБЗОР БАЗОВЫХ ПОНЯТИЙ ОБЪЕКТНО-ОРИЕНТИРОВАННОЙ МЕТОДОЛОГИИ.

Объектно-ориентированная терминология – неустоявшаяся, и в целом и в частности в Object Pascal (например, то что в Turbo Vision называлось «объект», теперь называется «класс», а термин «объект» используется в другом смысле).

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

Объект – экземпляр (instance) класса, можно понимать как данное типа класс, или даже как переменную типа класс.

Подкласс – Класс - Надкласс. Имеется тонкое различие между иерархиями «Часть – Целое» и «Конкретное – Абстрактное». Например, конкретная рука часть конкретного человека, абстрактная рука часть абстрактного человека, но конкретный человек не является частью абстрактного человека, если различать понятия «человек» и «человечество». Иерархия типов данных классического Паскаль – это иерархия вида «Часть – Целое». Она сохраняется в Object Pascal в классическом своем смысле (в том числе и для классов, и тем более для объектов). Связка понятий «Подкласс – Класс - Надкласс» основана на иерархии вида «Конкретное – Абстрактное». Эта связка – принципиально новое, что Object Pascal вводит в инструментарий программирования. Причем, вводит в употребление в явном виде, т.е. «можно писать в программе», а не просто «можно иметь в виду, но оставляя у себя в голове».

С этой иерархией в явное употребление вводятся понятия – родительский класс для класса (например, - «рыба» для - «лещ») и классы-потомки для класса (например, «Камский лещ» по утверждению моего дяди (*) не тоже самое, что «Волжский лещ», и конечно не те лещи-объекты, которых мы уже давно съели, уже потому - что «лещ» останется даже когда всех лещей съедят). Наконец, раз уж мы заговорили о «родителях», надо сказать о «наследовании» – понятие наследование (inheritance) тоже вводится в явное употребление, но конкретнее это мы рассмотрим попозже…

Компонентами (components) класса являются поля, методы и свойства.

Поля (fields) класса – можно понимать как поля записи (record), в определении класса поля объявляются также как поля записи.

Методы (methods) класса ~ процедуры и функции для работы с объектами класса, в определении класса объявляются только их заголовки.

Свойства (properties) класса ~ поля и процедуры-функции доступа к ним (access methods). Класс можно понимать как некий способ группировки данных и действий, свойства - как некий аналогичный способ группировки данных и действий, но на своем уровне и по своему критерию.

В классическом языке Паскаль встроенные способы группировки данных имеют встроенные средства доступа к компонентам – селекторы, на основе которых строятся компонентные переменные. Например, для массива x: array[1..10] of real имеется компонентная переменная x[3], в которой селектор [3] обеспечивает доступ к компоненту. Процедуры-функции доступа к компонентам объектов типа класс могут понадобиться, либо потому что класс сложно устроен, либо потому что есть основания защитить объект от прямого доступа к его компонентам – инкапсулировать его компоненты.

ОПРЕДЕЛЕНИЕ КЛАССА – конструкция раздела определений типов данных.

ИмяКласса = CLASS (ИмяРодительскогоКласса)

ОпубликованныеПоля-Методы-Свойства ;

PRIVATE ПриватныеПоля-Методы-Свойства ;

PUBLIC ОбщедоступныеПоля-Методы-Свойства ;

PROTECTED ЗащищенныеПоля-Методы-Свойства ;

PUBLISHED ОпубликованныеПоля-Методы-Свойства ;

AUTOMATED Поля-Методы-СвойстваOLE-механизма ;

END

(ИмяРодительскогоКласса) может отсутствовать.

Ключевые слова PRIVATE, PUBLIC, PROTECTED, PUBLISHED, AUTOMATED разбивают определение класса на секции, соответственно Приватных, Общедоступных, Защищенных, Опубликованных и OLE компонентов. Секции любого из этих видов могут отсутствовать или многократно повторяться в любом порядке. Компоненты, объявленные сразу после заголовка класса до первой (явной) секции, по умолчанию считаются Опубликованными при включенной директиве компилятора {$M+} или Общедоступными при выключенной директиве компилятора {$M-}.

С помощью секций специфицируется область видимости компонентов класса (scope visibility of class members), проще говоря, место - где и только где можно писать имя компонента класса. Это механизм инкапсуляции (encapsulation), аналогичный и дополнительный к возможностям модулей.

  • Общедоступные (PUBLIC) компоненты (объявленные в PUBLIC-секции) имеют базовый вариант области видимости, которая распространяется:

  1. от точки их объявления в классе до END класса;

  2. во всех описаниях реализации методов определяемого класса;

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

  1. во всех объектах определяемого класса своего модуля (или программы) и других, в которых этот модуль объявлен USES;

  2. аналогично, во всех классах-потомках и их объектах…

Опубликованные (PUBLISHED) и OLE (AUTOMATED) компоненты имеют такую же область видимости, но дополнительно имеют некоторую специфику, связанную соответственно с инструментарием визуального программирования и инструментарием для работы с OLE-компонентами.

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

  • Защищенные (PROTECTED) компоненты (аналогично PRIVATE-приватным) имеют область видимости, тоже ограниченную пределами модуля, в котором дано определение класса. Но определенные в других модулях классы-потомки этого класса «видят» эти PROTECTED-компоненты и могут их использовать, для потомков эти компоненты имеют как бы (базовую) PUBLIC-общедоступную область видимости. Эти тонкости в степени защищенности компонентов класса напрямую связаны с «третьим китом» объектно-ориентированной методологии – полиморфизм (polymorphism), дополнительно к инкапсуляции (encapsulation) и наследованию (inheritance).

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

Классы и модули. В Object Pascal 2 можно использовать классы, не использую модули, и наоборот. Однако наилучших результатов удается добиться, только продуманно комбинируя инструментарий классов и модулей. Естественные рекомендации общего характера – определения «внешних» классов включать в интерфейсные секции подходящих модулей, а описания тел методов (процедур-функций) и определения «внутренних» классов (и типов) в секции реализации этих модулей. При этом, используя секции классов можно дополнительно управлять степенью инкапсуляции компонентов класса (повысить защищенность).

ИСПОЛЬЗОВАНИЕ КЛАССА.

  • ИмяКласса является именем типа и может быть использовано как «имя типа» в соответствующих конструкциях языка (с некоторыми естественными ограничениями реализации языка).

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

  • Прямой доступ (если он разрешен) к компонентам объекта типа ИмяКласса осуществляется также как к полям записи:

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]