Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Объектно-ориентированные средства программирования.




Самитов Р.К.

Избранные средства OBJECT PASCAL 2

· языки программирования развиваются;

· причины на то – разнообразны и нередко противоречивы, поэтому развитие происходит в разных направлениях (*);

· Вирт Н. – после языка Pascal разработал несколько языков программирования, … Modula…

· Object Pascal 2 – разработка Borland Int. Inc. с учетом, как исследований самого Вирта, так и других рекомендаций современной методологии программирования.

МОДУЛИ

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

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

· данные и действия «ходят парочкой» – одно без другого не возможно;

· почти во всех рассуждениях хорошо просматривается отношение двойственности между этими понятиями – «что можно делать с данными, можно делать с действиями, и наоборот»;

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

ДАННЫЕДЕЙСТВИЯ

recordbegin …; … end

array, filefor, while, repeat

unionPascal имеется if, case

ограниченный вариант

– записи с вариантами)

рекурсивные структуры данных рекурсивные процедуры-функции

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

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


Хотелось бы сказать, модули (пакеты, кластеры,…) – аппарат языков программирования, предназначенный для определения и использования абстрактных типов данных (**). Однако реальность несколько иная, поэтому ограничимся менее категоричным утверждением. Если процедуры и функции, видимо достаточно адекватно соответствует понятию подзадача, то модули – видимо более соответствуют понятию набор инструментов для решения специализированного класса задач. Именно поэтому модули быстро вошли в практику программирования, как средство оформления разнообразных инструментальных библиотек – для работы с графикой, с базами данных, с объектами организации диалога (меню, окна,…) и т.д.

Описание модуля.

UNIT ИмяМодуля;

INTERFACE { Интерфейсная секция }

{ В этой секции описывается взаимодействие данного модуля с }

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

{ с главной программой. Другими словами – взаимодействие }

{ модуля с «внешней средой». }

USES ИмяДругогоМодуля, …; { Список импорта интерфейсной секции }

{ Здесь объявляются модули, средства которых используются в }

{ интерфейсной секции описываемого модуля. }

CONST { Список экспорта интерфейсной секции. Содержит }

TYPE { традиционные разделы Паскаль-программы, в которых }

VAR { определяются константы и типы, а также описываются }

PROCEDURE { переменные и заголовки(!!!) процедур и функций, }

FUNCTION { которые таким образом объявляются доступными }

{ из внешней среды. }

IMPLEMENTATION { Секция реализации }

{ В этой секции описываются данные и действия модуля, }

{ не видимые из вне, в частности, реализация процедур и }

{ функций, объявленных в интерфейсной секции. }

USES ИмяДругогоМодуля, …; { Список импорта секции реализации. }

{ Здесь объявляются модули, средства которых не используются }

{ явно в интерфейсной секции, но используются в секции }

{ реализации. }

LABEL { Разделы объявления, определения и описания }

CONST { внутренних для секции реализации данных и действий. }

TYPE { Содержит традиционные разделы Паскаль-программы в их }

VAR { традиционном синтаксисе и семантике. }

PROCEDURE { Заголовки процедур и функций, объявленных в }

FUNCTION { интерфейсной секции, здесь можно указать без списка }

{ параметров. }

INITIALIZATION { Секция инициализации – необязательная }

{ В эту секцию включаются действия, которые выполняются }

{ перед выполнением раздела операторов программы, в которой }

{ этот модуль объявлен предложением USES. }

FINALIZATION { Секция завершения – необязательная }

{ В эту секцию включаются действия, которые выполняются по }

{ окончании выполнения раздела операторов программы, в которой}

{ этот модуль объявлен предложением USES. }

END.

Использование модуля.

· В оформлении программы (!!! но не описаний процедур и функций) появился новый раздел – список импортируемых модулей:

USES ИмяМодуля, …;

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

· Имена объектов (типов, переменных, процедур…) модуля, доступные внешней среде, вне модуля используются с уточнением: ИмяМодуля. Имя

Подведем первые итоги.

· Синтаксически конструкция описания модуля похожа на конструкцию описания процедуры. Но по сути – существенно отличается:

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

· инструменты, которые модуль предоставляет другим, – константы, типы данных, переменные (для хранения данных), процедуры и функции (для преобразования данных), которые описаны в интерфейсной секции модуля; в традиционной системе понятий языка Паскаль эти переменные, процедуры и т.д. оказались бы локальными и были бы недоступны из вне!!!

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

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

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

ПРИМЕР. В теме «Данные типа ссылка и динамические структуры данных» мы рассматривали однонаправленные линейные списки. Здесь рассмотрим вариант модуля для работы такими списками и пример его использования – построение ряда Фаррея (который мы уже рассматривали в вышеупомянутой теме). PROGRAM\OOP\FARREJ.000\FARREJ.DPR

{Файл UGlob.PAS}

UNIT UGlob; { Это модуль «общих понятий» - для межмодульных связей, }

{ его можно сменить и основной модуль L1List, }

{ не требуя каких либо изменений, будет будет работать }

{ с однонаправленными линейными списками, хранящими не }

{ «числители и знаменатели», а другую информацию. }

INTERFACE

TYPE TVal= RECORD Ch,Zn:INTEGER END;

IMPLEMENTATION

END.

{Файл L1List.PAS}

UNIT L1List; { Это основной модуль примера – вариант инструментария }

{ для работы с однонаправленными линейными списками. }

INTERFACE

USES UGlob;

VAR CurVal:UGlob.TVal; { отсюда можно взять информацию текущего }

{ элемента списка - «числитель и знаменатель» }

PROCEDURE ResetList;

{Текущим устанавливается 1-й элемент списка}

{Его значение засылается в CurVal}

FUNCTION EOList: BOOLEAN;

{Проверяет наличие текущего элемента в списке}

FUNCTION ExistNext: BOOLEAN;

{Проверяет наличие следующего (за текущим) элемента в списке}

PROCEDURE GetNext;

{Текущим устанавливается следующий элемент списка}

{Его значение засылается в CurVal}


PROCEDURE InsPred(ValEl:UGlob.TVal);

{Вставляет перед(!) текущим новый элемент со значением из ValEl }

{!!! текущим остается тот, который был до, но предыдущим - новый}

PROCEDURE WriteAll(VAR TxtF:TextFile);

{Выводит в TxtF все элементы списка}

{!!! TxtF должен быть открыт для записи}

IMPLEMENTATION

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

VAR PFirst{ссылка на 1-й},PCur{ссылка на текущий},

PPred{ссылка на предшествующий текущему – приходится хранить, }

{т.к. есть желание иметь возможность вставлять новый }

{элемент не после, а перед текущим}:TPElem;

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

IF PCur<> NILTHEN CurVal:=PCur^.Inf

END;

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

FUNCTION ExistNext;

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

PROCEDURE GetNext; BEGIN

IF PCur<> NILTHENBEGIN PPred:=PCur; PCur:=PCur^.Next;

IF PCur<> NILTHEN CurVal:=PCur^.Inf

END

END;

PROCEDURE InsPred; VAR p:TPElem; BEGIN

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

IF PPred= NILTHEN PFirst:=p ELSE PPred^.Next:=p; PPred:=p

END;

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

WHILE p<> NILDOBEGIN

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

END; WRITELN(TxtF)

END {отметим, что при этом не «сбиты» значения PCur,PPred и т.д.};

INITIALIZATION {список пустой}

PFirst:= NIL;PCur:= NIL;PPred:= NIL;

FINALIZATION

END.

{Файл Farrej.DPR}

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

PROGRAM Farrej; { Это программа построения ряда Фаррея F(n), по }

{ алгоритму: F(1) = 0:1,1:1; F(i) строится по F(i-1)}

{ вставками между каждой парой соседних элементов }

{ a:b и c:d, таких что (b+d)=i, нового }

{ элемента (a+c):(b+d). }

USES SysUtils,UGlob,L1List;

VAR PredCur,x:UGlob.TVal; FIn,FOut:TextFile; i,n:INTEGER;

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

x.Ch:=1;{x.Zn:=1;}L1List.InsPred(x) {построили F(1)};

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 DOBEGIN {Строим F(i)}

L1List.WriteAll(FOut) {протокол для проверки – вывели F(i-1)};

L1List.ResetList {установились на начало списка};

REPEAT PredCur:=L1List.CurVal; L1List.GetNext {получили пару};

IF (PredCur.Zn+L1List.CurVal.Zn)=i THENBEGIN

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

L1List.InsPred(x) {вставили новый}

END

UNTILNOT L1List.ExistNext;

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

END.

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

· Как демонстрирует программа 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<> NILTHENBEGIN 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= NILTHEN List.PFirst:=p

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

END;

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

WHILE p<> NILDOBEGIN

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 DOBEGIN

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 THENBEGIN

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

L1List.InsPred(RFarrej,x)

END

UNTILNOT L1List.ExistNext(RFarrej);

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

END.


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

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

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

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

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

Становление технологий структурного проектирования в 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 -секции) имеют базовый вариант области видимости, которая распространяется:

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

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

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

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

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

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

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

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

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

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


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

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

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

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

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...