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

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 :=0 to count-1 do
  14. List.Add(PropList^[i].Name);
  15. FreeMem(PropList,Count*SizeOf(Pointer));
  16. end;
  17. procedure CloneObject(SrcObj,DesObj:TPersistent);
  18. var
  19. NameList:TStringList;
  20. I:Integer;
  21. V:Variant;
  22. begin
  23. if srcObj.ClassName<>DesObj.ClassName then
  24. raise Exception.Create(‘不同类型的对象,无法克隆‘);
  25. if (not Assigned(SrcObje)) or not (Assigned(DesObj)) then
  26. raise Exception.Create(‘对象不能为空‘);
  27. NameList := TStringlist.create;
  28. GetPropNames(SrcObj,NameList);
  29. try
  30. for I:= 0 to Namelist.Count-1 do
  31. begin
  32. V:= GetPropValue(SrcObj,Namelist.Strings[I]);
  33. SetPropValue(DesObj,NameList.Strings[I],V);
  34. finally
  35. Namelist.free;
  36. end;
  37. 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;

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 :=0 to count-1 do
  14. List.Add(PropList^[i].Name);
  15. FreeMem(PropList,Count*SizeOf(Pointer));
  16. end;
  17. procedure CloneObject(SrcObj,DesObj:TPersistent);
  18. var
  19. NameList:TStringList;
  20. I:Integer;
  21. V:Variant;
  22. begin
  23. if srcObj.ClassName<>DesObj.ClassName then
  24. raise Exception.Create(‘不同类型的对象,无法克隆‘);
  25. if (not Assigned(SrcObje)) or not (Assigned(DesObj)) then
  26. raise Exception.Create(‘对象不能为空‘);
  27. NameList := TStringlist.create;
  28. GetPropNames(SrcObj,NameList);
  29. try
  30. for I:= 0 to Namelist.Count-1 do
  31. begin
  32. V:= GetPropValue(SrcObj,Namelist.Strings[I]);
  33. SetPropValue(DesObj,NameList.Strings[I],V);
  34. finally
  35. Namelist.free;
  36. end;
  37. 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;

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

时间: 2024-10-18 05:21:51

浅拷贝与深度拷贝(原型模式)的相关文章

Python 直接赋值、浅拷贝和深度拷贝区别

Python 直接赋值.浅拷贝和深度拷贝区别 转自https://www.runoob.com/w3cnote/python-understanding-dict-copy-shallow-or-deep.html 直接赋值:其实就是对象的引用(别名). 浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象. 深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象. 解析 1.b = a: 赋值引用,a 和 b 都指向同一个对象. # -*- c

Python 直接赋值、浅拷贝和深度拷贝解析

直接赋值:其实就是对象的引用(别名). 浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象. 深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象. 字典浅拷贝实例 实例 >>> a = {1: [1,2,3]} >>> b = a.copy() >>> a, b ({1: [1, 2, 3]}, {1: [1, 2, 3]}) >>> a[1].append(4) >>

Python 直接赋值、浅拷贝和深度拷贝全解析

直接赋值:其实就是对象的引用(别名). 浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象. 深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象. 字典浅拷贝实例 实例 1 2 3 4 5 6 7 >>>a = {1: [1,2,3]} >>> b = a.copy() >>> a, b ({1: [1, 2, 3]}, {1: [1, 2, 3]}) >>> a[1].appe

学习python--第八天(直接赋值、浅拷贝和深度拷贝解析)

直接赋值:其实就是对象的引用(别名). 浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象.--只拷贝第一层 深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象.--克隆一份 原文地址:https://www.cnblogs.com/denny-djl/p/10348114.html

Perl的浅拷贝和深度拷贝

首先是深.浅拷贝的概念: 浅拷贝:shallow copy,只拷贝第一层的数据.Perl中赋值操作就是浅拷贝 深拷贝:deep copy,递归拷贝所有层次的数据,Perl中Clone模块的clone方法,以及Storable的dclone()函数是深拷贝 所谓第一层次,指的是出现嵌套的复杂数据结构时,那些引用指向的数据对象属于深一层次的数据.例如: @Person1=('wugui','tuner'); @Person2=('longshuai','xiaofang',['wugui','tun

JS对象的浅拷贝与深度拷贝

1.js中的6个标准类型 原始类型:Undefined.Null.Boolean.String.Number 引用类型:Object ( 最简单的引用类型var obj={} ) 2.把标准类型分成了两类.这两种类型复制克隆有很大区别 原始类型:存储的是对象的实际数据( 存放在栈内存中 ) 引用类型:存储的是对象的引用地址( 栈内存中存放的堆内存的地址 ) 3.克隆概念 浅度克隆:原始类型为值传递.对象类型仍为引用传递 深度克隆:所有的元素与属性均完全复制.与原对象完全脱离关系( 对新对象的修改

Python直接赋值、浅拷贝和深度拷贝解析

ython 文件 writelines() 方法用于向文件中写入一序列的字符串. 这一序列字符串可以是由迭代对象产生的,如一个字符串列表. 换行需要制定换行符 \n. 语法 writelines() 方法语法如下: 1fileObject.writelines(iterable)参数 iterable -- 可迭代对象(字符串.列表.元祖.字典). 返回值 该方法没有返回值. 原文地址:http://blog.51cto.com/98405/2145034

Android 原型模式

原型的是一种创建的设计模式,主用来创建的复杂的对象和构建耗时的实例.通过克隆已有的对象来创建的新的对象,从而节省时间和内存. 感谢 <JAVA与模式>之原型模式 原型的模式介绍 原型模式的uml图 - Client 客户端类调用的类 - Prototype 提供clone()等方法的原型抽象接口 - ConcretePrototype 具体的原型的函数 原型的栗子 案例分析:多账号系统管理 我们需要做一个的类似的多用户登陆的简单系统,我们只能够在我的里面去创建的用户,并修改用户的属性,再其他的

C#设计模式:原型模式(Prototype)及深拷贝、浅拷贝

原型模式(Prototype) 定义: 原型模式:用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象.被复制的实例被称为原型,这个原型是可定制的. Prototype Pattern也是一种创建型模式,它关注的是大量相同或相似对象的创建问题.应用原型模式就是建立一个原型,然后通过对原型来进行复制的方法,来产生一个和原型相同或相似的新对象,或者说用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象. 模式中的角色 抽象原型类(Abstract Prototype):提供一个克