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

ИНКАПСУЛЯЦИЯ

ООП требует чтобы данные были скрыты или инкапсулированы внутри использующего их класса. Использование методов доступамк внутренним данным объекта уменьшает шансы появления ошибок.(например класс TDate- методы могут проверить корректность изменения даты)

Инкапсуляция позволяет легко вносить изменения во внутреннюю структуру класса, не меняя его внешнее представление.

Таким образом, класс – это черный ящик, с небольшой видимой частью – интерфейсом класса. Интерфейс позволяет другим частям программы осуществлять доступ к объектам данного класса и использовать их. Это инкапсуляция, основанная на классах. Object Pascal позволяет использовать и другой подход – инкапсуляцию основанную на модулях.

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

Для поддержки инкапсуляции основанной на классах в Object Pascal введены следующие спецификаторы доступа:

Public - определяет поля и методы к которым может обращаться любая часть программы.

Private - отмечает поля и методы класса, которые не доступны в не модуля, в котором определен класс.

Protected - определяет частично доступные поля и методы, доступ к ним имеют только методы данного класса и всех производных классов.

Как правило все поля класса относятся к категории PRIVATE а методы объявляются с использованием спецификатора PUBLIC.(это нормальный стиль ООП)

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

Type TDate=class

private

month, day, year:integer

Public

Procedure SelValue(m,d,y:integer); overload;

Procedure SetValue(newDate:TDateTime); overload;

Function,,,,,,,,,,,,,,

Function…………….
procedure increase.

…………….

End;

Procedure TDate.SetValue(m,d,y:integer);

Begin

Fdate:=EncodeDate(y,m,d);

End;

В данном примере метод GetText возвращает дату в виде строки. Добавление функиций типа Getmonth getyear getday не целесообразно, так как функции реализующие прямой доступ ко всем полям подряд могут уменьшить эффект от инкапсуляции, усложнив изменение внутренней структуры класса(при необходимости);

Изменим внутреннюю структуру класса. Вместо полей введем новое поле типа TdateTime.

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

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

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

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

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;


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: