Вопрос управления объектами через интерфейсы в Delphi может показаться сложным для тех, кто не имеет достаточного опыта в этой области. В частности, проблема может заключаться в неправильном управлении ссылками, что приводит к преждевременному уничтожению объектов. В этом руководстве мы рассмотрим типичные подходы к работе с интерфейсами и предложим решения, которые помогут избежать распространенных ошибок.
Описание проблемы
Рассмотрим пример, когда в приложении используется интерфейс IListModel для визуализации данных. Класс MyModel реализует этот интерфейс и используется в приложении MyApp. При попытке показать данные, создается экземпляр виджета, который удерживает ссылку на модель через интерфейс IListModel. После закрытия виджета, ссылка на модель уничтожается, и сама модель также уничтожается, так как счетчик ссылок достигает нуля.
IListModel = interface
function At(row, col: Integer): String;
end;
MyModel = class(TInterfacedObject, IListModel)
public
function At(row, col: Integer): String;
procedure ManipulateA;
procedure ManipulateBogus;
end;
View = class(TForm)
public
constructor Create(model: IListModel); reintroduce;
end;
MyApp = class(...)
strict private
model: MyModel;
public
// ...
end;
procedure MyApp.ShowModel;
var
v: View;
begin
v := View.Create(model); // Ссылка на модель увеличивается
v.ShowModal;
FreeAndNil(v); // Ссылка на модель уменьшается до нуля
// Ошибка: модель уничтожена
end;
Подходы к решению
Использование интерфейсов вместо объектов
Чтобы избежать проблем с ссылками, рекомендуется хранить ссылки на объекты только через интерфейсы. В классе MyApp следует хранить ссылку на model через интерфейс IListModel, а не как экземпляр MyModel.
Можно отказаться от подсчета ссылок, переопределив методы _AddRef и _Release. Это поведение реализовано в классе TComponent, который не использует подсчет ссылок.
Использование TInterfacedPersistent
Для использования как интерфейсов, так и обычных ссылок, можно использовать класс TInterfacedPersistent, который позволяет управлять объектами с подсчетом ссылок, но также позволяет их освобождать вручную.
Альтернативный интерфейс IMyModel
Если необходимо использовать дополнительные методы, которые не объявлены в интерфейсе IListModel, можно создать новый интерфейс IMyModel, который будет включать эти методы.
IMyModel = interface
function At(row, col: Integer): String;
procedure ManipulateBogus;
end;
MyModel = class(TInterfacedObject, IListModel, IMyModel)
public
function At(row, col: Integer): String;
procedure ManipulateA;
procedure ManipulateBogus;
// Реализация методов интерфейса IMyModel
end;
Пример класса без подсчета ссылок
type
TNonRefCountingObject = class
public
function QueryInterface(const IID: TGUID; out Obj): HResult; override;
function _AddRef: Integer; override;
function _Release: Integer; override;
end;
Общие замечания
При работе с интерфейсами важно помнить, что они должны отражать суть объекта, который они представляют, и что попытки использования интерфейсов для операций, для которых они не предназначены, могут привести к ошибкам.
Использование константных параметров может ускорить выполнение кода, но также может привести к путанице и опасным ситуациям, таким как непреднамеренное удержание временных объектов.
Заключение
Управление объектами через интерфейсы в Delphi требует внимательного планирования и понимания механизмов подсчета ссылок. Следуя рекомендациям, описанным выше, можно избежать многих распространенных ошибок и обеспечить надежную работу приложения.
Управление объектами через интерфейсы в Delphi может быть непростой задачей, связанной с правильным управлением ссылками для избежания преждевременного уничтожения объектов.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.