Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Создание и удаление объектов



 

Объект " появляется на свет" в результате вызова специального метода, который инициализирует объект — конструктора.Созданный экземпляр уничтожается другим методом — деструктором:

AMyObject: = TMyObject.Create;

{ действия с созданным объектом }

AMyObj ect.Destroy;

Но, — скажет внимательный читатель, — ведь объекта еще нет, как мы можем вызывать его методы? Справедливое замечание. Однако обратите внимание, что вызывается метод TMyObject. Create, a нe AMyObject. Create.

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

Те, кто раньше использовал ООП в работе на C++ и особенно в Turbo Pascal, будьте внимательны: в Object Pascal экземпляры объектов могут быть только динамическими. Это означает, что в приведенном выше фрагменте переменная AMyObject на самом деле является указателем, содержащим адрес объекта.

В Object Pascal конструкторов у класса может быть несколько. Общепринято называть конструктор create (в отличие от Borland Pascal 7.0, где конструктор обычно назывался Init, и от C++, где его имя совпадает с именем класса). Типичное название деструктора — Destroy.

type

TMyObject = class(TObject)

MyField: Integer;

Constructor Create;

Destructor Destroy;

Function MyMethod: Integer;

end;

Для уничтожения экземпляра объекта рекомендуется использовать метод Free, который первоначально проверяет указатель (не равен ли он nil) и только затем вызывает Destroy:

AMyObject.Free;

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

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

Чтобы правильно проинициализировать в создаваемом объекте поля, относящиеся к классу-предку, нужно сразу же при входе в конструктор вызвать конструктор предка при помощи зарезервированного слова

inherited:

constructor TMyObject.Create;

begin inherited Create;

end;

Взяв любой из примеров, прилагаемых к этой книге или поставляемых вместе в Delphi, вы почти не увидите там вызовов конструкторов и деструкторов. Почему? Дело в том, что любой компонент, попавший при визуальном проектировании в ваше приложение из Палитры компонентов, включается в определенную иерархию. Иерархия эта замыкается на форме (класс TForm): для всех ее составных частей конструкторы и деструкторы вызываются автоматически, незримо для программиста. Кто создает и уничтожает формы? Это делает приложение (глобальный объект с именем Application). В файле проекта (с расширением dpr) вы можете увидеть вызовы метода Application. createForm, предназначенного для этой цели.

Что же касается объектов, создаваемых вами динамически (во время выполнения приложения), то здесь нужен явный вызов конструктора и метода Free.

Инкапсуляция

Инкапсуляция – это принцип ООП, объединяющий в одном классе данные и методы, манипулирующие этими данными и защищающие данные класса от внешнего воздействия.

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

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

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

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

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

Инкапсуляция — один из четырёх важнейших механизмов объектно-ориентированного программирования (наряду с абстракцией, полиморфизмом и наследованием).

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

Сокрытие реализации целесообразно применять в следующих целях:

· предельная локализация изменений при необходимости таких изменений,

· прогнозируемость изменений (какие изменения в коде нужно сделать для заданного изменения функциональности) и прогнозируемость последствий изменений.

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

TMyClass = class

Private

FMyField: Integer;

procedure SetMyField( const Value: Integer );

function GetMyField: Integer;

Protected

Public

property MyField: Integer read GetMyField write SetMyField;

end;

Для создания интерфейса доступа к скрытым полям в Delphi введены свойства.

Инкапсуляция и модули

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

Специфические особенности модуля заключаются в следующем:

1) модуль - это автономно компилируемая програмная единица;

2) информационные и управляющие связи между модулями требуют ис­пользования в его описании деклараций, которые в совокупности определяют оболочку модуля, регламентирующую такие связи;

3) сборка програмной системы из модулей связана с отдельным тех­нологическим этапом - компоновкой (линковкой) программы. Пра­ви­ла такой компоновки полностью определяются системой модульных оболочек.

Концепция оболочки реализуется декларациями импорта/экспорта, регламентирующими, какие объекты, определенные внутри модуля, мож­но использовать " за его пределами". Подобные декларации могут быть оформлены в разных видах. В Модуле-2, например, для этого ис­пользуется специальный вид описания модуля - так называемая спе­цифицирующая оболочка (оболочка опpеделений, DEFINITION MO­DU­LE). В этой оболочке пере­числяются объекты, экспортируемые из мо­дуля, и спе­ци­фи­ци­pу­ют­ся методы их использования (фак­тичес­ки, действия над объектами). Пpичем, спецификация пpоцедуpных мето­дов пpо­во­дит­ся на уpовне пpогpаммиста, использующего мо­дуль (пот­­­pеби­теля), котоpому пpедставляются только заголовки пpоцедуp для pаботы с экспоpтиpуемыми объектами, но не пpогpаммы их pеа­ли­за­ции. Напpимеp:

DEFINITION MODULE A;

EXPORT QUALIFIED B, C, D;

TYPE B;

VAR C: B;

PROCEDURE D(C: B);

END A.

В этом примере разрешено использование " за пределами" модуля A трех определенных в нем програмных объектов: типа В, пере­мен­ной С и процедуры D.

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

Подобные стилевые особенности экспорта определяются сле­ду­ю­щи­ми соображениями. Ведь переменная C в приведенном примере - соб­ственная (внутренняя) переменная модуля A, размещенная в его ста­тической памяти. Можно ли менять значение этой переменной за пределами модуля? Или это не соответствует общим " житейским" пред­ставлениям об экспорте? И вообще, что можно делать с пе­ре­мен­ной C за пределами модуля? Если что угодно, то какой смысл за­­водить C в модуле А? Если действия над C внутpи A рег­ла­мен­ти­ро­ваны процедурами A, то целесообразно экспортировать только та­кой регламент, т.е. процедуры. В любом случае переменная, оп­ре­де­ленная в одном модуле и используемая в другом, приобретает ха­рак­тер разделяемой переменной - с ней могут работать программы, определенные в различных модулях и, возможно, написанные разными людьми. Конечно, существуют ситуации, когда от такого экспорта не­­возможно или нецелесообразно отказываться, но, согласитесь, что в некоторых случаях он может быть похож на экспорт станков, которые используются как металлолом.

Для идентификации " своих" и " чужих" объектов (принадлежащих дру­гому модулю) могут использоваться две формы импорта/экспорта: квалифицированный и неквалифицированный. Первая форма связана с ис­пользованием ключевого слова QUALIFIED в предложении экспорта и позволяет обращаться к экспортируемым объектам только по их " вну­треннему" имени, без префиксации именем модуля-экспортера. Вторая форма не требует использования этого ключевого слова, но корректная идентификация экспортируемых объектов в этом случае всегда связана с префиксацией. Например, для использования пе­ре­мен­ной C за пределами специфицирующей оболочки, определенной вы­ше для модуля A, в случае квалифицированного экспорта достаточно простого именования C, а при неквалифицированном экспорте свя­за­но с использованием префиксированного имени A.C.

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

Закрытый экс­порт запрещает использование каких-либо операций над экс­пор­ти­руемыми объектами кроме тех, которые определены в модуле-экс­пор­теpе. В этом смысле закрытый экспорт - это " экспорт сырья", " пот­­ребительских продуктов" и т.п.

Закрытым экспортом обычно экспортируется тип данных, при этом в специфицирующей оболочке модуля отсутствует определение этого типа, он просто декларируется. В приведенном выше примере так экс­­пор­ти­руется тип В. Модула-2 разрешает такой экспорт для ссы­лоч­ных типов и некоторых отрезков типов. Вот, например, как может быть определен экспорт сигналов, используемых для синхронизации ква­зипараллельных процессов:

DEFINITION MODULE SINCHRON;

EXPORT QUALIFIED SIGNAL, SEND, WAIT;

TYPE SIGNAL;

PROCEDURE SEND (VAR S: SIGNAL);

PROCEDURE WAIT (VAR S: SIGNAL);

END SINCHRON.

Закрытость экспорта в этом модуле позволяет его рассматривать как полностью инкапсулиpованное определение абстрактного типа (ал­гебры) синхpонизиpущих сигналов. Все имманентные свойства объ­ектов-сигналов скрыты от пользователя (в реализующей оболочке модуля - IMPLEMENTATION) и лишь два метода (SEND и WAIT) вы­не­се­ны на экспорт. Закрытость экспорта разрешает над любыми сиг­на­ла­ми, определенными вне SINCHRON, выполнение только двух действий: SEND и WAIT; использование для этого каких-либо других процедур и/или опе­раторов языка невозможно.

Реализующие определения и имманентные свойства класса SIGNAL, оп­ределенные в модуле IMPLEMENTATION, уточняют определение сиг­на­ла SIGNAL = POINTER TO PASPORT (см. pазд.VII) и определяют все де­тали работы с объектами этого типа.

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

----

---------> --+ A ¦

¦ LTTT-

¦ -----> ----¦L---< ----

¦ --+- --^- --+-

¦ ¦ B ¦ ¦ C +--> --+ D ¦

¦ L-T-- LT-T- L-T--

¦ ¦ ¦ ¦ ¦

¦ --+- ¦ ¦ ¦

L-+ E +--> ---- ¦ ¦

L-T-- ¦ ¦

L----< -----+---------

-----^---

¦ SYSTEM ¦

L---------

Здесь главный модуль A использует модули B, C, D, E и системный мо­дуль SYSTEM. Стpелки показывают напpавление экспоpта пpогpам­м­ных объектов, инкапсулиpованных в соответствующих модулях. Стpу­к­туpа связей на этой иллюстpации хаpактеpизуется наличием ба­зо­вых модулей (из них стpелки только выходят), модулей веpхнего уpо­в­ня (он здесь один - A), в котоpые стpелки только входят, пу­тей между базовыми и веpхними модулями (SYSTEM-C-A), (SYSTEM-C-D-A), (SYSTEM-C-D-E-B-A и т.д.) и петель (C-D-E-C).

Несмотpя на то, что наличие петель, вообще говоpя, не явля­ет­ся фатальным пpи компоновке модели A из модулей нижних уpовней, тем не менее " pазвязка" таких петель связана с некотоpыми пpоб­ле­мами. Pеализационно и технологически они pешаются коppектным кон­стpуиpованием последовательности деклаpаций импоpта в модуле A. Методологически же любая петля отpажает некачественную де­ком­по­зицию задачи, непpодуманную иеpаpхию понятий и методов, свя­зан­ных с ее pешением. В этом плане лучшая схема импоpта-экспоpта дол­жна основываться на выделении пpогpаммных слоев, начиная с ба­зового уpовня и кончая веpхним, пpедметно-оpиентиpованным па­ке­том пpикладных пpогpамм. Пpи этом напpавление стpелок экспоpта должно быть только снизу-ввеpх от базового слоя к веpхним и, pа­­­зумеется, петли должны быть исключены.

Подобное pасслоение свойств на основе механизмов импоpта-экспоpта и инкапсуляции позволяет вести послойную pазpаботку пpо­­г­pамм модулей, отладку на pазных уpовнях и в конечном счете поз­воляет повысить надежность и коppектность pазpабатываемого па­кета пpогpамм.

Заключение

Объектно-оpиентиpованный подход к pазpаботке пpогpамм и свя­зан­­ный с ним стиль пpогpаммиpования, оpиентиpованный на объекты, основаны на концепции абстpагиpования типов. Модуль как пpо­г­pам­м­ный эквивалент класса объектов, инкапсулиpующий в себе опpе­де­ле­ние такого абстpактного типа, является в этом отношении той кон­­стpуктивной единицей в объектно-оpиентиpованном подходе, ко­то­­pая позволяет совеpшить естественный пеpеход от тpадиционного пpо­цедуpного пpогpаммиpования к констpуиpованию пакетов пpи­к­лад­ных пpогpамм путем их послойной pазpаботки и отладки.

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

Пpоцесс абстpагиpования является неотъемлемой частью ло­гичес­ко­­го мышления, и в этом отношении его pазвитие не имеет гpаниц, как и pазвитие пpоцесса познания вообще. Pеализация такого pазвития на ос­­­нове использования ЭВМ обеспечивает пpи этом не только (и не столь­ко) новые возможности пpогpаммиpования, сколько новые воз­мо­ж­ности моделиpования сложных объектов pеального миpа.

Директивы видимости

 

Помимо объявлений элементов класса (полей, методов, свойств) описание класса, как правило, содержит несколько директив, которые устанавливают степень видимости элементов класса в программе.Рассмотрим семантику директив видимости.1. Директива private.
Поля, свойства и методы, описанные в разделе private, называются личными или закрытыми. Сюда помещаются элементы (чаще всего поля), которые выполняют в объекте специфичные функции и которые поэтому целесообразно скрыть от других частей программы, либо такие элементы, для которых по ряду причин не следует разрешать доступ извне объекта.2. Директива public.
Элементы, описанные в разделе public, называются общедоступными. Они могут быть использованы всюду в программе. Поля, свойства и методы, расположенные сразу после заголовка класса, при выключенной директиве компилятора {$M-}, по умолчанию принимаются общедоступными.3. Директива protected.
Элементы класса, объявленные в разделе protected (защищенный), доступны только в классах, порожденных от исходного. Здесь размещаются элементы, которые важны лишь для функционирования объектов данного класса и его потомков. Обычно в секцию protected помещаются описания методов класса.4. Директива published.
Поля, свойства и методы, описанные в разделе published, называются опубликованными. Их область видимости эквивалентна области видимости общедоступных описаний. Отличие состоит в том, что информация о них, за исключением ряда типов, например real, на этапе проектирования программы помещается в инспектор объектов. Описания, расположенные сразу после заголовка класса, при включенной директиве компилятора {$M+}, по умолчанию принимаются опубликованными.
5. Директива automated.
Элементы класса, объявленные в разделе automated, называются автоматическими. Их область видимости эквивалентна области видимости общедоступных описаний. Отличие состоит в том, что для автоматических свойств и методов генерируется дополнительная информация, которая используется для реализацииOLE-механизма. Использовать директиву automated имеет смысл при объявлении потомков стандартного класса TAutoObject.
Ниже приведено описание класса TTPerson, в которое включены директивы видимости.

ТТРегsоп = class
private
FName: TName; { значение свойства Name }
FAddress: TAddress; ( значение свойства Address}
protected
Constructor Create(Name: TName);
Function GetName: TName;
Function GetAddress: TAddress;
Procedure SetAddress (NewAddress: TAddress);
Property Name: TName
read GetName;
Property Address: TAddress
read GetAddress
write SetAddress;
end;

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

Все что объявлено в секции protected, доступно как и в секции private, а также наследникам данного класса (интерфейс разработчика). Здесь можно объявить методы доступа к значениям свойств (если вы хотите позволить изменять эти методы потомкам вашего компенента), а также свойства, методы и события (методы реакции на события) в компонентах типа TCustomXXX.

Все что объявлено в секции public, доступно любому пользователю компонента (интерфейс этапа выполнения). Здесь объявляются, как правило методы.

В секции published можно объявлять только свойства и события (они объявляются в виде свойств). Они доступны во время проектирования приложения (интерфейс этапа проектирования).

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

С другой стороны, если слишком ограничить того, кто будет порождать классы-потомки, и не обеспечить ему достаточный набор инструментальных средств и свободу маневра, то он и не станет использовать ваш класс.

В модели объектов языка Object Pascal существует механизм доступа к составным частям объекта, определяющий области, где ими можно пользоваться (области видимости). Поля и методы могут относиться к четырем группам (секциям), отличающимся областями видимости. Методы и свойства могут быть общими (секция public), личными (секция private), защищенными (секция protected) и опубликованными (секция published). Есть еще и пятая группа, automated, она ранее использовалась для создания объектов СОМ; теперь она присутствует в языке только для обратной совместимости с программами на Delphi версий 3—5.

Области видимости, определяемые первыми тремя директивами, таковы.

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

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

§ Поля, свойства и методы секции protected также доступны только внутри модуля с описываемым классом. Но — и это главное — они доступны в классах, являющихся потомками данного класса, в том числе и в других модулях. Такие элементы особенно необходимы для разработчиков новых компонентов — потомков уже существующих. Оставляя свободу модернизации класса, они все же скрывают детали реализации от того, кто только пользуется объектами этого класса.

§ Три области видимости — private, protected, public — как бы упорядочены по возрастанию видимости методов. В классах-потомках можно повысить видимость методов и свойств, но не понизить ее. При описании дочернего класса можно переносить методы и свойства из одной сферы видимости в другую, не переписывая их заново и даже не описывая — достаточно упомянуть о нем в другом месте:

§ type

§ TFirstObj = class

§ private

§ FNumber: Integer;

§ protected

§ property Number: Integer read: FNumber;

§ end;

§...

§ TSecondObj = class(TFirstObj)

§ published

§ property Number;

§ end;

§ Если какое-либо свойство объекта из состава VCL принадлежит к области public, вернуть его в private невозможно. Напротив, обратная процедура широко практикуется в Delphi. У многих компонентов (например, TEdit) есть предок (в данном случае TCustomEdit), который отличается только отсутствием опубликованных свойств. Так что, если вы хотите создать новый редактирующий компонент, порождайте его на базе TCustomEdit и публикуйте только те свойства, которые считаете нужными. Разумеется, если вы поместили свойство в область private, " достать" его оттуда в потомках возможности уже нет.

 


Поделиться:



Популярное:

Последнее изменение этой страницы: 2016-07-14; Просмотров: 991; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.048 с.)
Главная | Случайная страница | Обратная связь