Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Delphi中设计一个界面来保存不同的集合?_Delphi_Collections_Interface - Fatal编程技术网

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

如何在Delphi中设计一个界面来保存不同的集合?,delphi,collections,interface,Delphi,Collections,Interface,我有多个收藏,如: TFooList = TObjectDictionary<string,TFoo>; TBarList = TObjectDictionary<string,TBar>; .... TRoot = class value : string end; TFoo = class(TRoot) ... end; TBar = class(TRoot) ... end; 因此,最后一部分将从每个集合继承,并创建save/load方法,将每个集合“

我有多个收藏,如:

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

TRoot = class
   value : string
end;

TFoo = class(TRoot)
...
end;

TBar = class(TRoot)
...
end;
因此,最后一部分将从每个集合继承,并创建save/load方法,将每个集合“转换”为/从TDictionary(string,string)

TFooListSavable=TFooList;
程序创建(保存\加载:ISave);
程序保存;
程序负载;
....
结束;
过程TFooListSavable.Save
// 1. 创建一个字典
// 2. 加载上面的字典和我的收藏
//将每个Foo对象转换为字符串
// 3. 调用save\u load.save(字典);
结束;
过程TFooListSavable.Load
// 1. 创建一个字典
// 2. 调用save_load.load加载它
// 3. 移动集合并将字符串转换为TFoo和
// 4. AddOrEquals将创建的每个TFoo添加到TFooListSavable中。
结束;
因此,这种方法有两个问题:

1) 保存或加载的接口需要集合中的字符串值,尽管每个集合中的所有对象都继承自定义了该字符串的类,但我不知道如何将像
TDictionary
这样的集合转换为
TDictionary
,而无需使用上面的代码(这将复制集合,以便将其传递给
iSave
对象)


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

我认为你这样做是错误的

ISave
不应该有任何
t词典的概念。它应该只公开用于读取/写入基本数据类型(整数、字符串等)的方法。让
t工具可存储
t工具可存储
根据需要调用
ISave
方法,决定如何序列化各自的
t词典
数据

如果
TFooListSavable
TBarListSavable
ISave
传递给每个
TFoo
/
TBar
并让他们直接序列化自己的数据成员,那就更好了

例如,类似这样的内容:

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=接口
函数HasData:Boolean;
程序StartWriteCollection;
程序开始编写项目;
过程FinishWriteCollection;
程序完成写入项;
过程writebolean(值:布尔);
过程WriteInteger(值:整数);
过程WriteString(常量值:字符串);
...
收集程序;
程序项目;
收集程序;
程序完成项目;
函数ReadBoolean:Boolean;
函数ReadInteger:Integer;
函数ReadString:String;
...
结束;
特鲁特=阶级
公众的
值:字符串;
构造函数创建;事实上的
过程保存(Dest:iseralize);事实上的
过程加载(Src:iseralize);事实上的
结束;
TBaseList=类(TObjectDictionary)
公众的
过程保存(Dest:iseralize);
过程加载(Src:iseralize);
结束;
TFoo=等级(特罗特)
公众的
myint:整数;
...
过程保存(Dest:iseralize);推翻
过程加载(Src:iseralize);推翻
结束;
TFooList=TBaseList;
TBar=等级(特鲁特)
mybool:布尔型;
...
过程保存(Dest:iseralize);推翻
过程加载(Src:iseralize);推翻
结束;
TBarList=TBaseList;
TDB序列化=类(TInterfacedObject,ISerialize)
...
结束;
TFileSerialize=class(TInterfacedObject,ISerialize)
...
结束;
过程TBaseList.Save(Dest:ISerialize);
变量
配对:TPair;
开始
目的地StartWriteCollection;
为自己做一对
开始
Dest.StartWriteItem;
目的写入限制(对密钥);
特鲁特(双人价值)。保存(目的地);
Dest.FinishWriteItem;
结束;
Dest.FinishWriteCollection;
结束;
过程TBaseList.Load(Src:iseralize);
变量
Cnt,I:整数;
键:字符串;
值:T;
开始
自我清晰;
Src.StartReadCollection;
而Src.HasData
开始
Src.StartReadItem;
key:=Src.ReadString;
值:=T.创建;
尝试
荷载值(Src);
添加(键、值);
除了
价值。自由;
提高;
结束;
Src.finishraditem;
结束;
Src.finishradcollection;
结束;
程序部队保存(目的地:ISerialize);
开始
目的写入限制(值);
结束;
程序组荷载(Src:ISerialize);
开始
值:=Src.ReadString;
结束;
过程TFoo.Save(Dest:iseralize);
开始
继承;
目的写入者(myint);
结束;
过程TFoo.Load(Src:iseralize);
开始
继承;
myint:=Src.ReadInteger;
结束;
程序TBar.Save(目标:ISerialize);
开始
继承;
目的地Writebolean(mybool);
结束;
程序TBar.Load(Src:ISerialize);
开始
继承;
mybool:=Src.ReadBoolean;
结束;

您有一个观点,即每个类(TFoo、TBar)都应该负责将自己转换为字符串。但您不认为集合的加载/保存过程有点“面向流”吗?我认为编写数据库版本(TDbSerialize)很难,不是吗?@MarcosCunhaLima不,我认为这一点都不难。我展示的只是一个例子。如果需要,您可以向
ISerialize
添加其他方法,以便DB实现可以为每个集合项创建新记录,然后
Write
方法可以根据需要更新记录列,然后在完成时提交。或者为要写入的整个集合创建新blob。你需要什么都行。
TDbSave = class( TInterfacedObject , ISave )
   ....
end; 
iSave := TDbSave( ConnString )

TFileSave = class( TInterfacedObject , ISave )
   ....
end; 
iSave := TFileSave( fileName );
    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; 
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;