Инкапсуляция и свойства объектов.
Классическое правило объектно-ориентированного программирования утверждает, что для обеспечения надежности нежелателен прямой доступ к полям. Всякое чтение и запись информации в поля должны осуществляться посредством вызовов соответствующих методов – правило инкапсуляции. Для реализации инкапсуляции в Object Pascal предусмотрена специальная конструкция. В Delphi пользователь объекта может полностью отторжен от его полей при помощи свойств. Свойства обычно характеризуются 3-мя элементами: поле и 2-мя методами, один из которых производит чтение информации из этого поля, а другой производит запись. type TAnObject = class (TObject) function GetAProperty: TSomeType; procedure SetAProperty (NewValue: TSomeType); property AProperty: TSomeType read GetAValue write SetAValue; end; В этом примере запись и чтение информации свойств осуществляется двумя методами. В написании этих методов в явном виде в программе нет необходимости. Достаточно указать AnObject.AProperty:=AValue; AVariable:=AnObject.Aproperty; Компилятор сам оттранслирует эти операторы вызовом соответствующих методов. Свойство внешне выглядит как поле, однако за каждым обращением к нему могут стоять вызовы внешних методов. В методах, осуществляющих обращение к полям объекта, может производиться проверка устанавливаемой величины на попадание в диапазон значений, а также вызов специальных процедур, зависящих от вносимых изменений. Если потребности в специальных процедурах чтения и записи нет, то вместо имен объектов могут быть использованы просто имена полей. type TPropObject = class (TObject) FValue: integer; procedure DoSomehing function Correct (AValue: integer): Boolean; procedure SetValue (NewValue: integer); property AValue: integer read FValue write SetValue; end; Чтение свойства означает чтение соответствующего поля, при установке значения вызываются?? Если свойство должно либо только читаться, либо только записываться, то в его описании может присутствовать только соответствующий метод.
type TPropObject = class (TObject) function GetAValue: TSomeType; property AValue: TSomeType read GetAValue; end; В этом примере свойство можно лишь прочитать. Попытка записи будет вызывать ошибку компиляции. Для установки значения свойства по умолчанию используют ключевое слово default. property FVisible: true read GetFVisible write SetFVisible default true; Это означает, что при запуске программы компилятором будет присвоено??. Свойство может быть и векторным. В этом случае внешне оно будет выглядеть как массив. Property APoint (Index: integer): TPoint read GetPoint write SetPoint; Хотя в реальности среди полей класса может и не быть полей типа массив. При помощи свойств вся обработка обращений к внутренним структурам класса может быть замаскирована. При использовании векторного свойства помимо задания??. В случае применения векторного свойства после слов read и write должны стоять имена методов. Применение имен полей в этом случае является недопустимым. Метод, читающий значение векторного свойства должен быть описан, как функция, возвращающая значение того же типа?? и тип которого должны совпадать с именем и типом индекса векторного свойства. function GetPoint (Index: integer): TPoint; По аналогии метод, производящий запись в векторное свойство должен быть описан как процедура с 2-мя параметрами. Первый параметр равносилен с именем и типом индекса векторного свойства. Тип второго равносилен с типом элемента векторного свойства. procedure SetPoint (Index: integer; NewPoint: TPoint);
Лекция 3. У векторных свойств есть еще одна важная особенность. В некоторых важных классах DELPHI (списки, наборы строк) построены вокруг одного векторного свойства. В этом случае один из методов такого класса дает доступ к некоторому массиву элементов, а остальные методы являются вспомогательными. Для облегчения написания программ такой метод может быть описан с использованием ключевого слова default.
type TMyObject = class (TObject) property Strings (Index: integer): string read Get write Pul default; end; Если в классе есть default-свойство, то при написании программы можно не указывать, а сразу ставить индекс? var AMyObject: TMyObject; AMyObject.Strings[1]:= ‘первый способ’; AMyObject[2]:= ‘второй способ’; В DELPHI 100% полей стандартных классов не доступно и заменены базирующимися на их основе свойствами. При разработке собственных классов рекомендуется придерживаться этого правила.
Наследование. Сущность этого принципа заключается в следующем. Если в программе создается новый класс, незначительно отличающийся от старого класса, то в программе можно заново не писать код, отвечающий за переопределение полей свойств и методов старого класса, а достаточно просто указать, что вновь создаваемый класс является наследником старого класса. type TNewObject = class (TOldObject) end; При этом во вновь создаваемом классе нужно доопределить поля, свойства и методы отсутствующие в старом классе, т.е. провести переход от общему к частному. В этом случае старый класс называется классом-предком или родительским классом, а вновь создаваемый – классом-потомком или дочерним классом. В языке Object Pascal все классы являются наследниками базового класса TObject. Поэтому если новый класс порождается непосредственно от класса TObject, то в описании нового класса его можно не указывать. type TMyObject = class; end; аналогично type TMyObject = class (TObject) end; Последняя запись является предпочтительней, т.к. устраняет неоднозначности. Все поля и методы, описанные в родительском классе доступны в классе-потомке без каких-либо ограничений. При этом если имена методов совпадают, то о таких методах говорят, что они перекрываются. Исключать члены родительских классов из списка наследования нельзя. В языке Object Pascal не допускается множественное наследование (объект наследует методы и поля от нескольких объектов). В зависимости от своего поведения при наследовании методы разделяются на 3 группы: ¨ Статические ¨ Виртуальные и динамические ¨ Перегружаемые (overload) Статические методы, а также любые поля в объектах-потомках при наследовании ведут себя одинаково. Можно без ограничений перекрывать методы, которые определены в классе-предке, и при этом изменять тип метода. В этом случае код метода в объекте-потомке будет полностью перекрывать одноименный метод объекта-предка.
type TFirstObject = class (TObject) i: extended; procedure SetData (AValue: extended); end; TSecondObject = class (TFirstObject); i: integer; procedure SetData (AValue: integer); end;
TFirstObject.SetData begin i:=1.0; end; TSecondObject.SetData begin i:=1; inherited SetData (0,99); end; В этом примере два разных метода с одним именем присваивают значения двум разным полям с именем i. Перекрытое, т.е. одноименное поле класса-предка недоступно в классе-потомке. В отличие от полей перекрытый метод доступен внутри других методов с помощью зарезервированного слова inherited. Все методы объекта по умолчанию являются статическими. Адрес их расположения в памяти определяется на стадии компиляции проекта, поэтому такие методы выполняются быстрее всего. В отличие от статических виртуальные и динамические методы. Для того, чтобы метод сделать виртуальным или динамическим нужно указать соответствующую директиву virtual, dynamic. С точки зрения принципа наследования поведение обеих видов методов одинаково. В классе-потомке могут быть перекрыты одноименными методами имеющими тот же тип. Применение виртуальных и динамических методов связано с 3-им свойством объектно-ориентированного программирования – полиморфизмом.
Полиморфизм.
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|