- •Методы объектов
- •Методы класса и данные класса
- •Инкапсуляция
- •Директивы видимости
- •Инкапсуляция при помощи свойств(новое в дельфи)
- •Свойства массивы
- •Многомерные массивы свойств
- •Индексированные свойства
- •Ссылочная модель Дельфи. (см тетрадь) Наследование
- •Наследование и совместимость типов
- •Безопасное преобразование типов
- •Интерфейсы
- •Технические приемы, связанные с реализацией интерфейса.
- •Обработка исключений.
- •Создание пользовательской особой (исключительной ситуации)
- •[]_[] Ссылки на классы []_[]
- •Создание компонентов при помощи ссылок на класс
- •Класс tObject
- •Конструктор Create класса tObject.
- •События.
- •Указатели на методы
- •If sender.InheritsFrom(tButton) then…
- •If sender is tButton then….
Инкапсуляция при помощи свойств(новое в дельфи)
Свойство - это имя скрывающее реализацию доступа к информации класса. Благодаря использованию свойств можно существенно модифицировать внутреннее строение класса не внося при этом каких либо изменений в код, использующий этот класс. Синонимом слова свойство является виртуальное поле.
С точки зрения пользователя класса свойство этого класса выглядит как поле – его значение можно считывать и записывать. Например,
Edit1.Text:=Button1.Caption;
Очень напоминает чтение и запись полей. Однако на самом деле внутренняя реализация доступа к свойству может быть разной.
1) Можно напрямую отобразить свойство на внутренние поля класса.
2) Можно назначить методы, которые должны использоваться для осуществления, чтения, и записи значений свойства. Если свойства отражены на методы, то в рамках этих методов может выполняться целый комплекс действий, связанных с доступом к значению свойства.
Например:
При этом может осуществляться доступ к каким либо другим данным не являющимся частью класса, может выполняться разнообразные дополнительные действия(побочные эффекты). Например – перерисовка элементов управления после модификации одного из его свойств.
Технически свойства – это идентификатор, который отображается на данные или методы при помощи специальных ключевых слов read и write , например.
Введем в класс Tdate свойство Month/
Есть специальное ключевое свойство PROPERTY
Property month:integer read Fmonth
Write SetMonth
Для чтения используется частное поле Fmonth, а для изменения его значения метод SetMonth. Этот метод должен быть определен внутри класса. Влзможна любая другая комбинация.
Например, метод можно использовать и для чтения и для записи.
Или наоборот читать при помощи метода а записывать при помощи поля.
Property Month: integer read GetMonth write SetMonth;
Property Month:integer read GetMonth write FMonth;
Использование метода для модификации значений свойства является общепринятой практикой.
Обычно связанные со свойством данные и методы являются частными PRIVATE или защищенными PROTECTED, а само свойство является общедоступным.(обычная практика ООП). Т..е. любой доступ к этим данным и методам осуществляется только с использованием свойств.
Инкапсуляция при помощи свойств является как упрощенной, так и расширенной.
+ Расширенной она является потому, что можно менять не только внутренне представление данных и функций доступа, но и добавлять новые функции доступа, не меняя при этом кода, который обращается к классу.
+ Упрощенной она является потому что в ситуациях, когда не требуется какого либо дополнительного кода, можно просто отобразить свойства на поля класса и не загромождать при этом внутреннее строение класса примитивными методами доступа к его внутренним полям.
Механизм завершения класса (ctrl shift C) может автоматически сформировать заготовки методов доступа к внутренним данным класса для любого из определенных свойств.
TMyClass
{ctrl shift C} /////// он добавит защищ.поле сам в определение класса
Property x:integer
End;
……………………
Implementation SetX;
…………………….
Procedure TMyclass
Begin
Fx:=Value;
End;
TMyclass
Private
FX:integer;
Procedure SetX(const value:integer);
Public
Property x:integer read FX write SetX;
End;
Примеры использования свойств:
1) класс TDate.
Type TDate = class
Private
fDate : TDateTime;
procedure SetDay(const Value:integer);
procedure SetMonth(const Value:ineteger);
procedure SetYear(const Value:integer);
function GetDay:integer;
function GetMonth: integer;
function GetYear:integer;
public
procedure SetValue( m,d,y : ineteger ); overload;
procedure SetValue(NewDate:TdateTime); overload;
function heapYear:Boolean;
function GetTex : string;
procedure Increase;
//////добавляем свойства(всё проектируем на методы.)
property Day:integer read GetDay write SetDay;
property Month:integer read GetMonth write SetMonth;
property Year:integer read GetYear write SetYear;
end;
Пример реализации методов Set Get
Function TdateGetMonth;
Begin
Result:=MonthOf(FDate); ///в модуле DateUtils.
End;
Procedure TDateSetMonth(const value:integer);
Begin
fDate:=recodeMonth(fDate,Value);
End;
*В процессе работы приложение должно создать объект класса TDate (обычно на методе OnCreate формы). В приложении он может выглядит например: поля редактирования для дня, месяца и года, из них можно читать значение и записывать их в свойства, а можно читать из свойств и записывать в эти поля. + на форме надо расположить кнопки, соответствующие методам класса(Increase…..). Т.е. надо полностью протестировать класс.
Пример обращения к свойству:
EdDay.Text:=IntToStr(ADay.Day);///происх обр к методу Get. Get выбир тек день…и т.п.
Aday.Year:=StrToInt(EdYear.Text);
При объявлении свойства директиву write можно не использовать. И тогда свойство будет предназначено только для чтения (read only). Точно так же и с директивой read(будет write only).
Пример 2:
1 из задач инкапсуляции – сокращение числа глобальных переменных, используемых программой.
Если мы меняем представление поля класса, то изменения зактрагивают код нескольких методов этого класса.
Т.е. сокрытие информации позволяет инкапсулировать изменения.
Пример:
1) В программе существует несколько форм. Некоторые данные можно сделать доступными для всех форм, описав их как глобальные переменные в секции Interface модуля одной из форм.
Var Form1:TForm1;
NClicks:integer;
Другие формы могут это использовать в своих целях. Данные связаны не с конкретным экземпляром формы, а со всей программой. Т.е. если есть 2 формы, они могут исп.эти данные совместно.
Если необходимо, чтобы каждая форма имела свой экземпляр данных, то необходимо добавить эти данные в класс формы.
Type TForm1=class(TForm)
Public
nClicks:integer;
end;
в этом случае при необходимости изменить внутреннюю структуру придется модифицировать код, использующий внутренние данные.
Таким образом данные можно объявить в Private и создать метод для чтения их значения.
Type TForm1=class(TForm)
private
nClicks:integer;
public
function GetClicks:integer;
end;
*Лучшим решением будет добавление свойства в форму.
Для этого
Type TForm1=class(TForm)
public
property NClick:integer;
end;
( и ctrl shift C)
Необходимо добавить обработку события OnClick для формы в рамках которого будет происходить увеличение значения свойства и отображение его значений в заголовке формы.
Procedure TForm1.FormClick(sender:object)
Begin
Inc(Nclicks);
Caption:=’Clicks’+IntToStr(Nclicks);
End;
Как создать еще одну формы такого же типа????
Procedure TForm1.btnCreateFormClick(sender:Tobject);
Begin
With TForm1.Create(Self) do
Show;
End;
3) Применение свойств для инкапсуляции доступа к компонентам формы.
Пример:
Имеется главная форма со строкой состояния в которой отображается информация, которая например может поступать из вспомогательных форм.
Main
Form1.StatusBar1.SimpleText:=’!!!’;
Если в дальнейшем возникнет потребность поменять интерфейс …..
Property Statustext:string
Read GetTExt write SetText;
…………………
Function TForm1.GetText;string;
Begin
Result:=StatusBar1.SimpleText;
End;
Procedure TFrom1.SetTex(const Value:integer)
Begin
StatusBar1.SimpleText:=Value;
End;