• 浅拷贝与深度拷贝(原型模式)


    Delphi的VCL从TPersistent开始支持RTTI(RuntimeTypeInfo)运行时类型信息,它是通过{$M+}编译指令提供了RTTI的功能.M打开以后,Delphi在编译该对象时,会把对象的类型信息编译进可执行文件,这样在运行时就可以动态地获得对象的属性和方法等信息.因为所有的VCL可视化组件都是从TPersistent派生的,因此可以将组件信息保存到dfm也可以动态加载.

    Delphi还定义了一个虚方法Assign,

    [delphi] view plain copy
     
    1. procedure Assign(Source:TPersistent);virtual;  

    这个方法就是用来把源对象属性复制到目标对象中的.默认的TPersistent对象的Assign方法只是简单的调用源对象的AssignTo方法来复制属性,而TPersistent的AssignTo方法只是抛出一个异常,没有实现有意义的功能,那么派生自TPersistent的对象要想提供克隆的功能都需要重载TPersistent的Assign或AssignTo来实现自定义的复制功能.

    获取类的属性列表:要引用TypInfo//rtti,contnrs,classes,sysutils;//{$M+}要打开.

    [delphi] view plain copy
     
    1. procedure GetPropNames(AObject:TObject;var List:TStringList);  
    2. var  
    3.   I,Count:Integer;  
    4.   PropList:PPropList;//数组型指针,数组又是指向属性的纪录型信息的指针型数组.  
    5.   PKinds:TTypeKinds;//类型信息的集合  
    6. begin  
    7.   List.Clear;  
    8.   PKinds := [tkUnknow,tkInteger,tkChar,tkEnumeration,tkFloat,tkString,tkSet,tkClass,tkMethod,tkWChar,tkLString,tkWString,  
    9. tkVariant,tkArray,tkRecord,tkInterface,tkInt64,tkDynArray];  
    10.   Count := GetPropList(AObject.ClassInfo,pKinds,nil);  
    11.   GetMem(PropList,Count*SizeOf(Pointer));  
    12.   GetPropList(AObject.ClassInfo,PKinds,PropList);  
    13.   for I :=to count-do  
    14.   List.Add(PropList^[i].Name);  
    15.   FreeMem(PropList,Count*SizeOf(Pointer));  
    16. end;  
    17.    
    18. procedure CloneObject(SrcObj,DesObj:TPersistent);  
    19. var  
    20.    NameList:TStringList;  
    21.   I:Integer;  
    22.   V:Variant;  
    23. begin  
    24.   if srcObj.ClassName<>DesObj.ClassName then  
    25.   raise Exception.Create('不同类型的对象,无法克隆');  
    26.   if (not Assigned(SrcObje)) or not (Assigned(DesObj)) then  
    27.   raise Exception.Create('对象不能为空');  
    28.   NameList := TStringlist.create;  
    29.   GetPropNames(SrcObj,NameList);  
    30.  try  
    31.    for I:= to Namelist.Count-do  
    32.   begin  
    33.       V:= GetPropValue(SrcObj,Namelist.Strings[I]);  
    34.      SetPropValue(DesObj,NameList.Strings[I],V);  
    35. finally  
    36.   Namelist.free;  
    37. end;  
    38. end;  

    其中GetPropName函数调用Delphi的TypeInfo单元的Rtti函数获得要克隆对象的保护级别为Published的属性名称字符串列表.而CloneObject则遍历对象的属性列表,使用RTTI函数GetPropValue通过属性名获得对象的属性值,然后通过RTTI函数的SetPropValue将获得源对象值赋值给目标对象.注意RTTI函数只对Published属性有效,其它保护级别的属性无效.

    上面的对象复制函数对于复合的对象如下级对象的TreeView,TStrings是无效的,对于这类对象还必须手工完成.procedure TStrings.Assign(Source:TPersistent);

    [delphi] view plain copy
     
    1. begin  
    2.   if Source is TStrings then  
    3.   begin  
    4.      Beginupdate;  
    5.     try  
    6.       Clear;  
    7.       FDefined:=TStrings(Source).FDefined;  
    8.       FNameValueSeparator := TStrings(Source).FNameValueSeparator;  
    9.       FQuoteChar := TStrings(Source).FQuoteChar;  
    10.       FDelimiter :=  TStrings(Source).FDelimiter;  
    11.       AddStrings(TStrings(Source));  
    12.     finally  
    13.       EndUpdate;  
    14.     end;  
    15.    Exit;  
    16.   end;  
    17.   inherited Assign(Source);  
    18. end;  
    19.    

    delphi的Assign方法除了可以实现同样类型对象的克隆之外,还可以实现不同对象之间的克隆,最典型的就是剪贴板TClipBoard了,Windows的剪贴板可以存放很不同类型的数据,如文本,位图,图元等,为了实现将剪贴板中的位图数据直接复制给对应的TBitmap或者TMetafile类,VCL重载了TClipboard类的AssignTo方法来实现将数据复制给不同的对象:

    [delphi] view plain copy
     
    1. procedure TClipboard.AssignTo(Dest: TPersistent);  
    2. begin  
    3.   if Dest is TPicture then  
    4.      AssignToPicture(TPicture(Dest))  
    5.   else if Dest is TBitmap then  
    6.      AssignToBitmap(TBitmap(Dest))  
    7.   else if Dest is TMetafile then  
    8.      AssignToMetafile(TMetafile(Dest))  
    9.   else inherited AssignTo(Dest);  
    10. end;  
    11. procedure TClipboard.AssignToBitmap(Dest: TBitmap);  
    12. var  
    13.   Data: THandle;  
    14.   Palette: HPALETTE;  
    15. begin  
    16.   Open;  
    17.   try  
    18.      Data := GetClipboardData(CF_BITMAP);  
    19.      Palette := GetClipboardData(CF_PALETTE);  
    20.      Dest.LoadFromClipboardFormat(CF_BITMAP, Data, Palette);  
    21.   finally  
    22.      Close;  
    23.   end;  
    24. end;  
    25. procedure TClipboard.AssignToMetafile(Dest: TMetafile);  
    26. var  
    27. //省略…  
    28. begin  
    29. //省略…  
    30. end;  
    31. procedure TClipboard.AssignToPicture(Dest: TPicture);  
    32. var  
    33. //…  
    34. Begin  
    35.   //省略…  
    36. end;  


     Delphi的VCL从TPersistent开始支持RTTI(RuntimeTypeInfo)运行时类型信息,它是通过{$M+}编译指令提供了RTTI的功能.M打开以后,Delphi在编译该对象时,会把对象的类型信息编译进可执行文件,这样在运行时就可以动态地获得对象的属性和方法等信息.因为所有的VCL可视化组件都是从TPersistent派生的,因此可以将组件信息保存到dfm也可以动态加载.
    Delphi还定义了一个虚方法Assign,procedure Assign(Source:TPersistent);virtual;
    这个方法就是用来把源对象属性复制到目标对象中的.默认的TPersistent对象的Assign方法只是简单的调用源对象的AssignTo方法来复制属性,而TPersistent的AssignTo方法只是抛出一个异常,没有实现有意义的功能,那么派生自TPersistent的对象要想提供克隆的功能都需要重载TPersistent的Assign或AssignTo来实现自定义的复制功能.

    获取类的属性列表:要引用TypInfo//rtti,contnrs,classes,sysutils;//{$M+}要打开.

    [delphi] view plain copy
     
    1. procedure GetPropNames(AObject:TObject;var List:TStringList);  
    2. var  
    3.   I,Count:Integer;  
    4.   PropList:PPropList;//数组型指针,数组又是指向属性的纪录型信息的指针型数组.  
    5.   PKinds:TTypeKinds;//类型信息的集合  
    6. begin  
    7.   List.Clear;  
    8.   PKinds := [tkUnknow,tkInteger,tkChar,tkEnumeration,tkFloat,tkString,tkSet,tkClass,tkMethod,tkWChar,tkLString,tkWString,  
    9. tkVariant,tkArray,tkRecord,tkInterface,tkInt64,tkDynArray];  
    10.   Count := GetPropList(AObject.ClassInfo,pKinds,nil);  
    11.   GetMem(PropList,Count*SizeOf(Pointer));  
    12.   GetPropList(AObject.ClassInfo,PKinds,PropList);  
    13.   for I :=to count-do  
    14.   List.Add(PropList^[i].Name);  
    15.   FreeMem(PropList,Count*SizeOf(Pointer));  
    16. end;  
    17.    
    18. procedure CloneObject(SrcObj,DesObj:TPersistent);  
    19. var  
    20.    NameList:TStringList;  
    21.   I:Integer;  
    22.   V:Variant;  
    23. begin  
    24.   if srcObj.ClassName<>DesObj.ClassName then  
    25.   raise Exception.Create('不同类型的对象,无法克隆');  
    26.   if (not Assigned(SrcObje)) or not (Assigned(DesObj)) then  
    27.   raise Exception.Create('对象不能为空');  
    28.   NameList := TStringlist.create;  
    29.   GetPropNames(SrcObj,NameList);  
    30.  try  
    31.    for I:= to Namelist.Count-do  
    32.   begin  
    33.       V:= GetPropValue(SrcObj,Namelist.Strings[I]);  
    34.      SetPropValue(DesObj,NameList.Strings[I],V);  
    35. finally  
    36.   Namelist.free;  
    37. end;  
    38. end;  



    其中GetPropName函数调用Delphi的TypeInfo单元的Rtti函数获得要克隆对象的保护级别为Published的属性名称字符串列表.而CloneObject则遍历对象的属性列表,使用RTTI函数GetPropValue通过属性名获得对象的属性值,然后通过RTTI函数的SetPropValue将获得源对象值赋值给目标对象.注意RTTI函数只对Published属性有效,其它保护级别的属性无效.
    上面的对象复制函数对于复合的对象如下级对象的TreeView,TStrings是无效的,对于这类对象还必须手工完成.

    [delphi] view plain copy
     
    1. procedure TStrings.Assign(Source:TPersistent);  
    2. begin  
    3.   if Source is TStrings then  
    4.   begin  
    5.      Beginupdate;  
    6.     try  
    7.       Clear;  
    8.       FDefined:=TStrings(Source).FDefined;  
    9.       FNameValueSeparator := TStrings(Source).FNameValueSeparator;  
    10.       FQuoteChar := TStrings(Source).FQuoteChar;  
    11.       FDelimiter :=  TStrings(Source).FDelimiter;  
    12.       AddStrings(TStrings(Source));  
    13.     finally  
    14.       EndUpdate;  
    15.     end;  
    16.    Exit;  
    17.   end;  
    18.   inherited Assign(Source);  
    19. end;  
    20.    

    delphi的Assign方法除了可以实现同样类型对象的克隆之外,还可以实现不同对象之间的克隆,最典型的就是剪贴板TClipBoard了,Windows的剪贴板可以存放很不同类型的数据,如文本,位图,图元等,为了实现将剪贴板中的位图数据直接复制给对应的TBitmap或者TMetafile类,VCL重载了TClipboard类的AssignTo方法来实现将数据复制给不同的对象:

    [delphi] view plain copy
     
      1. procedure TClipboard.AssignTo(Dest: TPersistent);  
      2. begin  
      3.   if Dest is TPicture then  
      4.      AssignToPicture(TPicture(Dest))  
      5.   else if Dest is TBitmap then  
      6.      AssignToBitmap(TBitmap(Dest))  
      7.   else if Dest is TMetafile then  
      8.      AssignToMetafile(TMetafile(Dest))  
      9.   else inherited AssignTo(Dest);  
      10. end;  
      11. procedure TClipboard.AssignToBitmap(Dest: TBitmap);  
      12. var  
      13.   Data: THandle;  
      14.   Palette: HPALETTE;  
      15. begin  
      16.   Open;  
      17.   try  
      18.      Data := GetClipboardData(CF_BITMAP);  
      19.      Palette := GetClipboardData(CF_PALETTE);  
      20.      Dest.LoadFromClipboardFormat(CF_BITMAP, Data, Palette);  
      21.   finally  
      22.      Close;  
      23.   end;  
      24. end;  
      25. procedure TClipboard.AssignToMetafile(Dest: TMetafile);  
      26. var  
      27. //省略…  
      28. begin  
      29. //省略…  
      30. end;  
      31. procedure TClipboard.AssignToPicture(Dest: TPicture);  
      32. var  
      33. //…  
      34. Begin  
      35.   //省略…  
      36. end;  

    http://blog.csdn.net/sushengmiyan/article/details/7467196

  • 相关阅读:
    python函数嵌套的实用技术
    windows10 装linux子系统
    彻底测试全部拷贝list相关操作的区别python
    c语言学习
    Pickling
    Filenames and paths
    Format operator
    Reading and writing
    Persistence
    Automation testing tool comparison
  • 原文地址:https://www.cnblogs.com/findumars/p/5183711.html
Copyright © 2020-2023  润新知