Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Сохранение и загрузка различных коллекций в формате TDictionary через интерфейс ISave в Delphi

Delphi , Компоненты и Классы , Коллекции

Возникает ситуация, когда необходимо сохранить и загрузить различные коллекции в формате TDictionary<string, string> через интерфейс ISave в Delphi. В данной статье мы рассмотрим, как это можно сделать, а также обсудим альтернативный подход к решению этой задачи.

Проблема

У нас есть несколько коллекций, каждая из которых представляет собой словарь с ключами в виде строк и значениями в виде пользовательских типов:

TFooList = TObjectDictionary<string, TFoo>;
TBarList = TObjectDictionary<string, TBar>;
...

Также у нас есть базовый класс TRoot и производные классы TFoo и TBar, которые наследуются от него:

TRoot = class
  value: string;
end;

TFoo = class(TRoot)
  ...
end;

TBar = class(TRoot)
  ...
end;

Мы имеем интерфейс ISave, который позволяет сохранять и загружать коллекции:

ISave = interface
  procedure Save(TDictionary<string, string>);
  function Load: TDictionary<string, string>;
end;

При этом интерфейс ожидает в качестве параметра словарь с ключами в виде строк и значениями в виде строк.

Мы уже реализовали несколько классов, которые реализуют этот интерфейс для сохранения и загрузки коллекций в файл или базу данных:

TDbSave = class(TInterfacedObject, ISave)
  ...
end;

TFileSave = class(TInterfacedObject, ISave)
  ...
end;

Теперь нам нужно как-то "перевести" наши коллекции в формат TDictionary<string, string> и обратно, чтобы использовать их с интерфейсом ISave.

Подход 1: Наследование и переопределение методов

Один из подходов - наследовать каждый тип коллекции и добавить методы Save и Load, которые будут "переводить" коллекцию в нужный формат и обратно. Например:

TFooListSavable = TFooList;
procedure Create(save_load: ISave);
procedure Save;
procedure Load;
...
end;

procedure TFooListSavable.Save
  // 1. создать TDictionary<string, string>
  // 2. загрузить этот словарь из нашей коллекции, переводя каждый объект Foo в строку
  // 3. вызвать save_load.Save(dictionary);
end;

procedure TFooListSavable.Load
  // 1. создать TDictionary<string, string>
  // 2. вызвать save_load.Load(), чтобы загрузить его
  // 3. пройтись по коллекции и перевести строки в объекты TFoo
  // 4. добавить каждый созданный объект TFoo в TFooListSavable.
end;

Однако у этого подхода есть две проблемы:

  1. Интерфейс ISave ожидает в качестве параметра словарь с ключами и значениями в виде строк. Несмотря на то, что все объекты в коллекциях наследуются от класса TRoot, в котором определена строка, мы не знаем, как преобразовать коллекцию типа TDictionary<string, TFoo> в TDictionary<string, string> без дублирования коллекции, чтобы передать ее объекту iSave.
  2. Хотя мы можем Replace iSave объекты, меняя способ сохранения/загрузки коллекций без изменения самих коллекций, мы не уверены, является ли этот подход лучшим для сохранения/загрузки коллекций, содержащих связанные объекты.

Альтернативный ответ: Переопределение методов в самих объектах коллекции

Вместо того чтобы наследовать каждый тип коллекции и добавлять методы Save и Load, мы можем переопределить эти методы непосредственно в самих объектах коллекции. Для этого нам понадобится интерфейс ISerialize, который будет определять методы для чтения/записи базовых типов данных (целых чисел, строк и т.д.). Каждый объект коллекции сможет самостоятельно решать, как сериализовать свои данные, вызывая методы интерфейса ISerialize по мере необходимости.

Давайте рассмотрим пример, как это можно реализовать:

type
  ISerialize = interface
    function HasData: Boolean;
    procedure StartWriteCollection;
    procedure StartWriteItem;
    procedure FinishWriteCollection;
    procedure FinishWriteItem;
    procedure WriteBoolean(value: Boolean);
    procedure WriteInteger(value: Integer);
    procedure WriteString(const value: String);
    ...
    procedure StartReadCollection;
    procedure StartReadItem;
    procedure FinishReadCollection;
    procedure FinishReadItem;
    function ReadBoolean: Boolean;
    function ReadInteger: Integer;
    function ReadString: String;
    ...
  end;

  TRoot = class
  public
    value: string;
    constructor Create; virtual;
    procedure Save(Dest: ISerialize); virtual;
    procedure Load(Src: ISerialize); virtual;
  end;

  TBaseList<T: TRoot, constructor> = class(TObjectDictionary<string, T>)
  public
    procedure Save(Dest: ISerialize);
    procedure Load(Src: ISerialize);
  end;

  TFoo = class(TRoot)
  public
    myint: Integer;
    ...
    procedure Save(Dest: ISerialize); override;
    procedure Load(Src: ISerialize); override;
  end;

  TFooList = TBaseList<TFoo>;

  TBar = class(TRoot)
    mybool: Boolean;
    ...
    procedure Save(Dest: ISerialize); override;
    procedure Load(Src: ISerialize); override;
  end;

  TBarList = TBaseList<TBar>;

  TDbSerialize = class(TInterfacedObject, ISerialize)
    ...
  end;

  TFileSerialize = class(TInterfacedObject, ISerialize)
    ...
  end;

procedure TBaseList<T>.Save(Dest: ISerialize);
var
  pair: TPair<string, T>;
begin
  Dest.StartWriteCollection;
  for pair in Self do
  begin
    Dest.StartWriteItem;
    Dest.WriteString(pair.Key);
    TRoot(pair.Value).Save(Dest);
    Dest.FinishWriteItem;
  end;
  Dest.FinishWriteCollection;
end;

procedure TBaseList<T>.Load(Src: ISerialize);
var
  Cnt, I: Integer;
  key: string;
  value: T;
begin
  Self.Clear;
  Src.StartReadCollection;
  While Src.HasData do
  begin
    Src.StartReadItem;
    key := Src.ReadString;
    value := T.Create;
    try
      value.Load(Src);
      Self.Add(key, value);
    except
      value.Free;
      raise;
    end;
    Src.FinishReadItem;
  end;
  Src.FinishReadCollection;
end;

procedure TRoot.Save(Dest: ISerialize);
begin
  Dest.WriteString(value);
end;

procedure TRoot.Load(Src: ISerialize);
begin
  value := Src.ReadString;
end;

procedure TFoo.Save(Dest: ISerialize);
begin
  inherited;
  Dest.WriteInteger(myint);
end;

procedure TFoo.Load(Src: ISerialize);
begin
  inherited;
  myint := Src.ReadInteger;
end;

procedure TBar.Save(Dest: ISerialize);
begin
  inherited;
  Dest.WriteBoolean(mybool);
end;

procedure TBar.Load(Src: ISerialize);
begin
  inherited;
  mybool := Src.ReadBoolean;
end;

В данном примере мы определили интерфейс ISerialize, который позволяет сериализовать и десериализовать объекты. Каждый объект коллекции может самостоятельно решать, как сериализовать свои данные, вызывая методы интерфейса ISerialize. Это позволяет нам сохранить и загрузить коллекции в формате TDictionary<string, string> через интерфейс ISave в Delphi.

Заключение

В данной статье мы рассмотрели проблему сохранения и загрузки различных коллекций в формате TDictionary<string, string> через интерфейс ISave в Delphi. Мы обсудили два подхода к решению этой задачи: наследование и переопределение методов в классах коллекций и переопределение методов непосредственно в самих объектах коллекции. Второй подход основан на использовании интерфейса ISerialize, который позволяет сериализовать и десериализовать объекты. Это позволяет нам сохранить и загрузить коллекции в нужном формате через интерфейс ISave в Delphi.

Создано по материалам из источника по ссылке.

В данной статье рассматривается проблема сохранения и загрузки различных коллекций в формате `TDictionary` через интерфейс `ISave` в Delphi, а также обсуждаются два подхода к решению этой задачи: наследование и переопределение методов в кл


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




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


:: Главная :: Коллекции ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-07-29 22:39:42/0.0085480213165283/1