Технические приемы, связанные с реализацией интерфейса.


Пример: будет основан на использовании 2х интерфейсов, IWalker и IJumper. Определим их:

Type IWalker = interface

[‘{ - - -}’]

Function Walk:string;

Function Run: string

Procedure SetPos(Value:integer);

Function GetPos:integer;

Property Position: integer read GetPos write SetPos;

End;

 

IJumper = interface

[‘{ - - -}’]

Function Jump:string;

Function Walk: string

Procedure SetPos(Value:integer);

Function GetPos:integer;

Property Position: integer read GetPos write SetPos;

End;

 

 

В примерах, в интерфейсах определяется свойство Position. Свойство интерфейса – это просто имя, отображаемое на методы read и write, нельзя отразить свойство на поле, т.к. интерфейс не может обладать полем.

 

Приведем пример реализации интерфейса IWalker

TRunner = class (TInterfacedObject, IWalker)

Private

Pos:integer;

Public

Function Walk:string;

Function Run:string;

Procedure SetPos(value:integer);

Function GetPos:integer;

End;

//Один класс реализует один интерфейс напрямую.

Интерфейс IJumper реализуем в 2х разных классах, воспользуемся след. походом: можно делегировать реализацию интерфейса, поддерживаемого некоторым классом объекту, входящему в состав этого класса. При этом доступ к этому объекту осуществляется с использованием свойства. Таким образом код реализации интерфейса будет частью нескольких классов. Для реализации такого подхода используется директива implements.

Пример:

TMyJumper = class (TInterfacedObject, Ijumper)

Private

FJumpImpl : IJumper; //переменная интерфейсного типа

Public

Constructor Create;

Property Jumper: IJumper read FJumpImpl implements IJumper;

End;

// делегирует внутреннему объекту который реализуется через свойство.

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

constructor TMyJumper.Create;

Begin

fJumppImpl:=TjumperImpl.Create{класс в котором будет реализ.внутрненний объект}

End;

 

Разработаем класс, реализующий интерфейс IJumper.

Type

TjumpImpl = class(TInterfacedObject, IJumper)

Private

Pos:integer;

Public

Function Jump:string;

Function Walk:string;

Procedure SetPos(Value:integer);

Function GetPost:integer;

End;

 

Если использовать данный код, программа откомпилируется, и заработает без каких - либо видимых проблем. Однако, проверив работу механизма подсчета ссылок, нужно убедиться, что он работает некорректно.

Проблема заключается в том, что когда программа извлекает интерфейс IJumper из объекта TMyJumper, она на самом деле увеличивает и уменьшает счетчик ссылок внутреннего, а не внешнего объекта. Т.е. у нас имеется единый комплексный объект и 2 независимых друг от друга счетчика ссылок. В рез – е объекты данного класса либо слишком долго хранятся в памяти, либо слишком рано уничтожаются. Чтобы решить проблему, необходимо использовать только один счетчик ссылок и перенаправить вызовы _AddRef и _Release {увел или уменьш ссылок} внутреннего объекта внешнему. Существует класс TAgregatedObject, который … Этот класс разработан специально для того, чтобы учитывать ситуацию, когда есть единый класс, состоящий из двух. В результате, в нашей реализации изменится следующее:

Type

TjumpImpl = class(TAgregatedObject, IJumper)

Private

Pos:integer;

Public

Function Jump:string;

Function Walk:string;

Procedure SetPos(Value:integer);

Function GetPost:integer;

End;

 

Объект, который использует данный класс для того чтобы реализовать интерфейс IJumper {в примере этот объект имеет класс TMyJumper} должен обладать конструктором Create для того, чтобы создать внутренний объект и деструктором для того чтобы его уничтожить. Конструктор внутреннего объекта в качестве параметра должен принимать контейнерный объект, благодаря чему у него появится возможность перенаправлять вызовы IInterface.

Приведем окончательную версию класса TMyJumper:

TMyJumper = class (TInterfacedObject, Ijumper)

Private

Pos:integer;

Public

Constructor Create;

FJumpImpl : TJumperImpl; //переменная интерфейсного типа

Property Jumper: TJumperimpl read FJumpImpl implements IJumper;

Destructor Destroy; override;

End;

 

Constructor TMyJumper.Create;

Begin

fJumpImpl:=TJumpImpl.Create(self);

End;

 

Пример #3

Разработаем класс, реализующим оба интерфейса IWalker и IJumper. Один интерфейс реализуем напрямую а другой через делегирование.

TAthlete = class (IInterfacedObject, IWalker, IJumper)

Private

fJumpImpl:=IJumperImpl;

public

constructor Create;

destructor Destroy; override;

function Run:string;virtual;

function IWalker.Walk:=Walk1;

function Walk1: string; virtual;

procedure SetPos(Value:Integer);

function GetPos:integer;

property Jumper: TJumperImpl read fJumpImpl implements IJumper;

End;

Один интерфейс, IWalker реализован напрямую, а реализация интерфейса IJumper делегирована внутреннему объекту fJumpImpl. Реализуя два интерфейса с общим методом(методы имеют одинаковое имя - Walk) можно придти к конфликту имён (особенно если оба интерфейса реализуются напрямую). Решение заключается в переименовании, в данном случае одного из методов при помощи псевдонима (Walk1).

В реализации всех методов класса TAthlete следует обратиться к свойству Position внутреннего объекта fJumpImpl иначе можно получить, что один атлет обладает двумя позициями.

Procedure TAthlete.GetPos;

Begin

Result:=fJumpImpl.Position;

End;

 

Function TAthlete.Run:string;

Begin

fJumpImpl.Position:= fJumpImpl.Position +2;

Result:= IntToStr(fJumpImpl.Position)+’Бежит’;

End;

 

 

TMyJumper.Create; Walk __ __
MyJumper
Athlete
Runner

 


*По нажатию кнопки:

1) Создается объект соответ.класса. В ListBox записывается строка что он создан. Затем вызываются по очереди методы данного класса, которые являются функциями типа string и их значение записывается в ListBox. Также записываются значения свойства Position, каждый метод увеличивает его на определенное число значений. Плюс описание требуемого перемещения. И обязательно деструктор.

 



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


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

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

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

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