Современные технологии программирования |
Конспект лекций |
Лекция 6. Свойства
Изучаемые вопросы: * Изучаемые понятия: * Тезисы * Понятие свойства * Классификация свойств * Переопределение свойств * Контрольные вопросы * Источники дополнительных сведений *
Понятие свойства
Классификация свойств
Переопределение свойств
Простые свойства
Свойства - масивы
Свойства – со спецификатором index
Свойство
Метод для чтения
Метод для записи
Индексное свойство
Понятие инкапсуляции и хороший стиль объектно-ориентированного программирования требует, чтобы обращение к полям объектов выполнялось исключительно посредством методов. Для обеспечения такой дисциплины программирования в синтаксис классов языка Object Pascal введена директива private, ограничивающая доступ к полям и методам класса из других модулей и конструкция свойство (property).
Свойства можно (достаточно условно) рассматривать как мини-модуль внутри класса, который ограничивает доступ к полям. При такой условной трактовке поле будет как бы внутренним для класса разделом реализации, а свойство – интерфейсным разделом, обеспечивающим доступ к этому полю с помощью строго указанных методов. Более того, в синтаксисе описания свойства в явном виде указывается метод доступа для чтения и метод доступа для записи значения свойства, что позволяет описывать свойства, доступные только для чтения или для записи. Кроме того свойства предоставляют дополнительные возможности реализации визуального программирования, для поддержки которого была введена стандартная директива published.
Перечислим возможности новой конструкции “свойство” более подробно:
Обобщая описанные преимущества свойств, можно сделать вывод, что свойства служат, с одной стороны, для ограничения доступа к полям и для повышения надёжности создаваемых программ, а с другой стороны, для разработки собственных компонентов, свойства которых станут доступны через object Inspector интегрированной среды Delphi.
Синтаксис допускает достаточно большое число вариантов записи свойств. Чтобы было легче в этом разобраться, проведём классификацию свойств. Свойства можно разделить по четырём различным признакам:
Сделанная по указанным признакам классификация показана на рисунке
Пример 1. Свойства типа класс
Приведённое в примере приложение демонстрирует работу памяти на одно значение типа простая дробь. Простую дробь, которую пользователь введёт в компонент однострочный редактор можно сохранить в памяти “MS”, добавить к содержимому памяти (M+), взять из памяти (MR), и, наконец, память можно очистить (MC). При выполнении команды взять из памяти, значение простой дроби, которое копируется из памяти, заносится в компонент однострочный редактор. Что бы очистить однострочный редактор необходимо нажать командную кнопку “Очистить”.
Для реализации операций над простыми дробями в состав приложения включён модуль UFrac, в котором описан класс TFrac, реализующий операции для работы с простыми дробями. Операции работы с памятью реализованы с помощью класса TMemory, который описан в модуле UMemory. Простые дроби, которые вы собираетесь заносить в память или добавлять к содержимому памяти, вам необходимо ввести с клавиатуры, отделяя числитель от знаменателя символом “/”. Значение простой дроби, которая хранится в памяти, вы можете просмотреть с помощью команды “MR”. Эта команда копирует содержимое памяти. Затем полученное значение отображается в однострочном редакторе. Когда память выключена, в ней хранится значение “0/1”.
Для записи в память и чтения из памяти в классе TMemory, реализующем работу с памятью, описано поле типа TFrac – простая дробь и свойство Memory, посредством которого осуществляется запись простых дробей (объектов типа TFrac)и считывание их из памяти.
Рисунок 1. Главная форма приложения для работы с памятью на одно значение типа простая дробь (TFrac) .
//---------------------------------------------------------------------------
program PExmpl2;
uses
Forms,
Uexmpl2 in 'Uexmpl2.pas' {Form1},
UMemory in 'UMemory.pas',
UFrac in 'UFrac.pas';
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
//---------------------------------------------------------------------------
unit Uexmpl2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons, UMemory, UFrac;
type
TForm1 = class(TForm)
SpeedButton1: TSpeedButton;
SpeedButton2: TSpeedButton;
SpeedButton3: TSpeedButton;
SpeedButton4: TSpeedButton;
StaticText1: TStaticText;
Edit1: TEdit;
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure SpeedButtonClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
M: TMemory;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//---------------------------------------------------------------------------
procedure TForm1.FormCreate(Sender: TObject);
begin
M:= TMemory.Create;
StaticText1.Caption:= M.MemOn
end;
//---------------------------------------------------------------------------
procedure TForm1.SpeedButtonClick(Sender: TObject);
var a: integer;
begin
a:= (Sender as TControl).Tag;
case a of
1: M.Memory:= TFrac.Create(Edit1.Text);
2: Edit1.Text:= M.Memory.Frac;
3: M.MemAdd(TFrac.Create(Edit1.Text));
4: M.MemClear;
end;
StaticText1.Caption:= M.MemOn
end;
//---------------------------------------------------------------------------
procedure TForm1.Button1Click(Sender: TObject);
begin
Edit1.Text:= '';
end;
//---------------------------------------------------------------------------
end.
//---------------------------------------------------------------------------
unit UFrac;
interface
Uses SysUtils,Dialogs;
type
TFrac = class
private
FN,FD: Real;
function GetFrac: String;
procedure SetFrac(newn: String);
public
constructor Create(Nr: Real = 0;Dr: Real = 1);overload;
constructor Create(f: String);overload;
function Add(b: TFrac): TFrac;
property Frac: String read GetFrac write SetFrac;
function Copy: TFrac;
end;
implementation
//---------------------------------------------------------------------------
constructor TFrac.Create(f: String);
begin
SetFrac(f);
end;
//---------------------------------------------------------------------------
constructor TFrac.Create(Nr,Dr: Real);
begin
FN:= Int(Nr);
FD:= Int(Dr);
end;
//---------------------------------------------------------------------------
function TFrac.add;
var c,e: Real;{c+d}
begin
c:= FN * b.FD + FD * b.FN;
e:= FD * b.FD;
result:= TFrac.Create(c,e);
end;
//---------------------------------------------------------------------------
function TFrac.GetFrac;
var s: String;
begin
s:= FloatToStr(FN) + '/' + FloatToStr(FD);
Result:= s
end;
//---------------------------------------------------------------------------
procedure TFrac.SetFrac;
var
n: Integer;
z: String;
begin
try
n:= System.Pos('/',newn);
FN:= StrToInt(System.Copy(newn,1,(n - 1)));
Delete(newn,1,n);
FD:= StrToInt(System.Copy(newn,1,Length(newn)));
except
on EConvertError do ShowMessage('?????? ?????')
end;
end;
//---------------------------------------------------------------------------
function TFrac.Copy: TFrac;
begin
result:= TFrac.Create(self.FN,self.FD);
end;
end.
//---------------------------------------------------------------------------
unit UMemory;
interface
uses UFrac;
type
MemoryState = (_OFF,_ON);
TMemory = class
private
MemState: MemoryState;
Mem: TFrac;
procedure MemStore(n: TFrac);
Function MemRestore: TFrac;
Function GetMemState: String;
public
property MemOn: String read GetMemState ; //write MemState;
property Memory: TFrac read MemRestore write MemStore; //write MemState;
procedure MemAdd(n: TFrac);
procedure MemClear;
constructor Create;
destructor Destroy;override;
end;
//---------------------------------------------------------------------------
implementation
//---------------------------------------------------------------------------
constructor TMemory.Create;
begin
MemState:= _OFF;
Mem:= TFrac.Create();
end;
//---------------------------------------------------------------------------
destructor TMemory.Destroy;
begin
Mem.Free;
end;
//---------------------------------------------------------------------------
procedure TMemory.MemAdd;
var a: TFrac;
begin
if n = nil then exit;
a:= Mem.Add(n); Mem.Free; Mem:= a;
MemState:= _ON
end;
//---------------------------------------------------------------------------
procedure TMemory.MemStore;
begin
if n = nil then exit;
Mem.Free;
// mem:= nil;
mem:= n.Copy;
MemState:= _ON
end;
//---------------------------------------------------------------------------
procedure TMemory.MemClear;
begin
MemState:= _OFF;
mem.Create();
end;
//---------------------------------------------------------------------------
Function TMemory.MemRestore;
begin
Result:= Mem.Copy;
end;
//---------------------------------------------------------------------------
Function TMemory.GetMemState: String;
begin
Result:= '';
if MemState = _On then Result:= 'M';
end;
end.
//---------------------------------------------------------------------------
Пример 2. Класс TLength (длина), TCircle (окружность).
Класс TLength позволяет работать с длинами, выраженными в сантиметрах или дюймах. Такая возможность предоставляется пользователю объектов класса за счёт применения различных свойств. Эти свойства позволяют читать и писать длину в числовом (Dm, Sm) или строковом (SmStr, DmStr) форматах, а также в сантиметрах (Sm) или дюймах (Dm). Класс TCircle позволяет моделировать в программе окружность с радиусом, представленным объектом класса TLength.
//--------------------------Длина-----------------------------------------------
unit ULength;
//--------------------------Длина-----------------------------------------------
interface
uses SysUtils;
const d = 2.54;//коэффициент пересчёта из дюймов в сантиметры
type
//------------------------------------------------------------------------------
TLength = class
private
Fa: real;//длина в сантиметрах
function GetSmStr:string;
procedure PutSmStr(newA:string);
function GetDmStr:string;
procedure PutDmStr(newA:string);
function GetDm:real;
procedure PutDm(newA:real);
public
property SmStr:string read GetSmStr write PutSmStr;
property DmStr:string read GetDmStr write PutDmStr;
property Dm: real read GetDm write PutDm;
property Sm: real read Fa write Fa;
constructor create(l: real);
function Copy(): TLength;
end;
//------------------------------------------------------------------------------
var
L : TLength;
//------------------------------------------------------------------------------
implementation
//------------------------------------------------------------------------------
constructor TLength.Create(l: real);
begin
Sm:= l;
end;
//------------------------------------------------------------------------------
function TLength.Copy(): TLength;
begin
Result:= TLength.Create(Fa);
end;
//------------------------------------------------------------------------------
function TLength.GetDmStr:string;
begin
GetDmStr:= FloatToStr(Fa/d);
end;
//------------------------------------------------------------------------------
procedure TLength.PutDmStr(newA:string);
begin
Fa:= StrToFloat(newa)/d
end;
//------------------------------------------------------------------------------
function TLength.GetSmStr:string;
begin
GetSmStr:= FloatToStr(Fa);
end;
//------------------------------------------------------------------------------
procedure TLength.PutSmStr(newA:string);
begin
Fa:= StrToFloat(newa)
end;
//------------------------------------------------------------------------------
function TLength.GetDm:real;
begin
GetDm:= Fa/d;
end;
//------------------------------------------------------------------------------
procedure TLength.PutDm(newA:real);
begin
Fa:= newa*d
end;
initialization
finalization
end.
//------------------------------------------------------------------------------
unit UCircle;
//--------------------Окружность------------------------------------------------------
interface
uses ULength;
type
//------------------------------------------------------------------------------
TCircle = class
private
FRadius: TLength;
function GetRadius: TLength;
procedure SetRadius(n: TLength);
public
property Radius: TLength read GetRadius write SetRadius;
function Square(ch: Char): Real;
function Perimetr(ch: Char): Real;
constructor Create(r: Real = 0);
destructor Destroy; override;
end;
//------------------------------------------------------------------------------
var Circle: TCircle;
//------------------------------------------------------------------------------
implementation
//------------------------------------------------------------------------------
constructor TCircle.Create;
begin
FRadius:= TLength.create(r);
end;
//------------------------------------------------------------------------------
destructor TCircle.Destroy;
begin
FRadius.Free;
end;
//------------------------------------------------------------------------------
function TCircle.Square;
begin
case Ch of
's','S': result:= pi * System.Sqr(FRadius.Sm);
'd','D': result:= pi * System.Sqr(FRadius.Dm);
else result:= -1
end;
end;
//------------------------------------------------------------------------------
function TCircle.Perimetr;
begin
case Ch of
's','S': result:= 2 * pi * FRadius.Sm;
'd','D': result:= 2 * pi * FRadius.Dm;
else result:= -1
end;
end;
//------------------------------------------------------------------------------
function TCircle.GetRadius: TLength;
begin
result:= FRadius//TLength.Create(FRadius.Sm)
end;
//------------------------------------------------------------------------------
procedure TCircle.SetRadius(n: TLength);
begin
FRadius.Free;
FRadius:= n.Copy;
end;
//------------------------------------------------------------------------------
end.
//------------------------------------------------------------------------------
unit UniProp;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ULength, UCircle;
type
TForm1 = class(TForm)
Edit1: TEdit;
Label1: TLabel;
Button1: TButton;
Edit3: TEdit;
Label3: TLabel;
Edit5: TEdit;
Label5: TLabel;
Edit6: TEdit;
Label6: TLabel;
Edit7: TEdit;
Edit8: TEdit;
Label4: TLabel;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
Circle.Free;
Circle:= TCircle.Create;
Circle.Radius:= TLength.create(StrToFloat(Edit1.Text));
Edit3.Text:= Circle.Radius.DmStr;
Edit5.Text:= FloatToStr(Circle.Square('s'));
Edit6.Text:= FloatToStr(Circle.Perimetr('s'));
Edit7.Text:= FloatToStr(Circle.Square('d'));
Edit8.Text:= FloatToStr(Circle.Perimetr('d'));
end;
end.
Объявление свойства, которое имеет такой же идентификатор, как и у свойства одного из родительских классов называется переопределением свойства. При переопределении свойства его интерфейс и спецификаторы могут не указываться.
Переопределение свойства при объявлении класса-потомка предоставляет программисту следующие возможности:
Источники дополнительных сведений