如何在Delphi中设计单个界面来保存不同的集合?

时间:2016-06-08 21:51:30

标签: delphi collections interface

我有多个集合,如:

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

TRoot = class
   value : string
end;

TFoo = class(TRoot)
...
end;

TBar = class(TRoot)
...
end;

我有一个可以保存或加载集合的接口/类:

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

请注意,界面需要键/字符串对集合才能正常工作。

我实现了一些ISave类,以便将集合加载到文件或数据库中/从文件或数据库中保存:

TDbSave = class( TInterfacedObject , ISave )
   ....
end; 
iSave := TDbSave( ConnString )

TFileSave = class( TInterfacedObject , ISave )
   ....
end; 
iSave := TFileSave( fileName );

因此,最后一部分将从每个集合继承并创建保存/加载方法,以便&#34;翻译&#34;每个集合进入/来自TDictionary(字符串,字符串)

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

   procedure TFooListSavable.Save
      // 1. create a  TDictionary<string, string>
      // 2. load the dictionary above with my collection translating
      //    each Foo object into a string
      // 3. call save_load.Save( dictionary );
   end;    
   procedure TFooListSavable.Load
      // 1. create a  TDictionary<string, string>
      // 2. call save_load.load to load it 
      // 3. Move over the collection and translate string into TFoo and
      // 4. AddOrEquals each TFoo created into TFooListSavable.
   end; 

所以,我对这种方法有两个问题:

1)保存或加载的接口需要Collection中的字符串值,虽然每个集合中的所有对象都继承自定义了此字符串的类,但我不知道如何转换集合之类的TDictionary<string,TFoo> TDictionary<string,string>不使用上面的代码(将复制集合以将其传递给iSave对象)。

2)我觉得,虽然我可以替换iSave个对象来改变保存/加载集合的方式而不改变集合本身,但我不知道这是否是保存的最佳方法/ load集合保留相关对象。

1 个答案:

答案 0 :(得分:2)

我认为你这样做是错误的。

ISave根本不应该有任何TDictionary的概念。它应该只公开读/写基本数据类型(整数,字符串等)的方法。让TFooListSavableTBarListSavable决定如何序列化他们想要的TDictionary数据,并根据需要调用ISave方法。

如果TFooListSavableTBarListSavableISave传递给每个人TFoo / TBar,并让他们直接序列化自己的数据成员,那就更好了。< / p>

例如,像这样:

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;