Инкапсуляция при помощи свойств(новое в дельфи)


Свойство - это имя скрывающее реализацию доступа к информации класса. Благодаря использованию свойств можно существенно модифицировать внутреннее строение класса не внося при этом каких либо изменений в код, использующий этот класс. Синонимом слова свойство является виртуальное поле.

С точки зрения пользователя класса свойство этого класса выглядит как поле – его значение можно считывать и записывать. Например,

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;

 

Свойства массивы

Предоставляют возможность ссылаться на множество значений свойства, используя одно и то же имя свойства. Каждое указываемое значение в массиве определятся отдельным индексом. Массив свойств объявляется также как и обычные свойства, только с небольшими отличиями.

1. После имени массива свойств необходимо определить список индексных параметров.

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

2. Спецификации методов чтения и записи (если определены) должны ссылаться только на метод доступа.

3. В качестве индекса можно указывать необязательно скалярный тип, например можно указывать строку.

4. На массив свойств нельзя ссылаться как на единое целое.

 

Пример:

Unit Warray1;

Interface

TvectorClass=class

private

Fvector:array[1..10] of word;

Protected

Function CutVector(Index: integer):word;

Procedure SetVector(Index:Integer; Value:word);

Procedure AddToVectorElem(Index:Integer; Value:word);

Public

Property Elementy[Index:Integer]:word read GetVector write SetVector; default;

Property AddToElements[Index:integer]:word write AddToVectorElem;

End;

 

Var Form: TForm1;

myVector: TVectorClass;

implementation

function TvectorClass.GetVector;

begin

Result:=GetVector[index];

end;

 

procedure TVectorClass.SetVector;

begin

Fvector[index]:=value;

end;

 

procedure TVectorClass.SetToVectorElements;

begin

Fvector[index]:= Fvector[index]*value;

end;

 

procedure TFrom1.FormCreate(…);

var i:integer; s:string;

begin

myVector:=TVectorClass.Create;

for i:=1 to 10 do

myVector[i]:=I; ////в данном случае присваивается

значение свойства Elements. Т.к.это свойство было объявлено с директивой default (свойство по умолчанию), то имя свойства можно опустить.

2ой вариант использования:

For i:=1 to 10 do

Begin

Form1.Memo1.lines.Add( IntToStr(MyVector.Elements[i]) );

End;

////

For i:=1 to 10 do

MyVector.AddToElements[i]:=5; //т.к. не свойство по умолчанию то обязательно указать имя свойства

end;

myVector.Free;

end;

 

Директива default в свойствах массивах не является спецификатором хранения как в обычных свойствах.

 

*Спецификаторы хранения default, stored, nodefault. Они могут быть использованы только для свойств не являющихся составными структурами данных и используются библиотекой VCL для управления автоматическим сохранением значений свойств в файле формы.

Смысл коротко: когда происходит в файле формы состояния компонент, то просматриваются все опубликованные свойства (те которые видно в инсп объектов).

Если такое свойство не имеет спецификатора stored или имеет его, но значение Boolean величины стоящей после него = false, то свойства не сохраняются. Если же результат = true, то текущее значение свойства сравнивается со значением по умолчанию установленным спецификатором default. Если эти значения равны то свойства не сохраняются. Если же не равны или default отсутствует то сохраняются. Спецификатор nodefault имеет чисто декаративный смысл и говорит о отсутствии спецификатора default.

В свойствах массивах эта директива говорит о свойстве по умолчанию и разрешает опускать имя свойства.!



Дата добавления: 2016-07-27; просмотров: 1469;


Поиск по сайту:

Воспользовавшись поиском можно найти нужную информацию на сайте.

Поделитесь с друзьями:

Считаете данную информацию полезной, тогда расскажите друзьям в соц. сетях.
Poznayka.org - Познайка.Орг - 2016-2024 год. Материал предоставляется для ознакомительных и учебных целей.
Генерация страницы за: 0.027 сек.