Современные технологии программирования
Конспект лекций
назад | содержание | вперед

Лекция 6. Свойства

Содержание

Введение *

Изучаемые вопросы: *

Изучаемые понятия: *

Тезисы *

Понятие свойства *

Классификация свойств *

Переопределение свойств *

Контрольные вопросы *

Источники дополнительных сведений *

 

Введение

  1. Изучаемые вопросы:
  2. Понятие свойства

    Классификация свойств

    Переопределение свойств

    Простые свойства

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

    Свойства – со спецификатором index

  3. Изучаемые понятия:
  4. Свойство

    Метод для чтения

    Метод для записи

    Индексное свойство

  5. Тезисы

 

Понятие свойства

Понятие инкапсуляции и хороший стиль объектно-ориентированного программирования требует, чтобы обращение к полям объектов выполнялось исключительно посредством методов. Для обеспечения такой дисциплины программирования в синтаксис классов языка Object Pascal введена директива private, ограничивающая доступ к полям и методам класса из других модулей и конструкция свойство (property).

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

Перечислим возможности новой конструкции “свойство” более подробно:

  1. Свойства ограничивают доступ к полям, указывая конкретные методы для чтения и для записи значения поля.
  2. Свойства могут быть объявлены с характеристиками только для чтения и только для записи.
  3. Методы доступа к свойству могут быть объявлены виртуальными, что предоставляет дополнительную гибкость в программировании.
  4. Свойства могут оказывать побочные эффекты, которые выражаются в том, что изменение значения свойства во время выполнения приводит к одновременному изменению внешнего вида компонента на экране монитора.
  5. Некоторые свойства могут быть сделаны доступными на этапе разработки проекта посредством их помещения в часть published-описаний, тогда как обычные поля объектов могут быть доступны только во время выполнения.
  6. При создании собственных компонентов, после того, как они будут помещены на палитру компонентов интегрированной среды Delphi, их опубликованные свойства становятся доступны через инспектор объектов Object Inspector.

Обобщая описанные преимущества свойств, можно сделать вывод, что свойства служат, с одной стороны, для ограничения доступа к полям и для повышения надёжности создаваемых программ, а с другой стороны, для разработки собственных компонентов, свойства которых станут доступны через object Inspector интегрированной среды Delphi.

    1. Классификация свойств

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

Сделанная по указанным признакам классификация показана на рисунке

Пример 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.

 

Переопределение свойств

Объявление свойства, которое имеет такой же идентификатор, как и у свойства одного из родительских классов называется переопределением свойства. При переопределении свойства его интерфейс и спецификаторы могут не указываться.

Переопределение свойства при объявлении класса-потомка предоставляет программисту следующие возможности:

 

Контрольные вопросы

  1. Что такое класс?
  2. Как описывается класс?
  3. Что такое поле?
  4. Что такое метод?
  5. Что такое свойство?
  6. Как создаются объекты?
  7. Как уничтожаются объекты?
  8. Что содержит переменная объектового типа?
  9. Как распределяется память под объект
  10. Что такое RTTI класса?
  11. Что такое инкапсуляция?
  12. Какой класс является общим предком по умолчанию?

Источники дополнительных сведений

 

 

наверх


назад | содержание | вперед