可变类型的 Map - hprose/hprose-delphi GitHub Wiki
Hprose 除了提供了方便的可变类型的 List,还提供了非常好用的可变类型的 Map。可变类型的 Map 也是基于接口来实现的,因此也具有引用计数的自动内存管理功能。
继承关系图
+----------------+ +-------------------+ +----------------+
| IReadWriteSync | | TInterfacedObject | | IMapEnumerator |
+----------------+ +-------------------+ +----------------+
| |
v v
+------+ +--------------+ +----------------------+
| IMap |--------->| TAbstractMap |<----------| IInvokeableVarObject |
+------+ +--------------+ +----------------------+
| |
| | +-------------------------+
+--------+---------------------+-------------->| ICaseInsensitiveHashMap |
| | | +-------------------------+
| | | |
| v v v
| +----------+ +----------+ +-------------------------+
+--| IHashMap |--------->| THashMap |--------->| TCaseInsensitiveHashMap |
+----------+ +----------+ +-------------------------+
| |
| | +---------------------------+
+---------+---------------------+------------>| ICaseInsensitiveHashedMap |
| | | +---------------------------+
| | | |
| v v v
| +------------+ +------------+ +---------------------------+
+--| IHashedMap |------->| THashedMap |------>| TCaseInsensitiveHashedMap |
+------------+ +------------+ +---------------------------+
IMap 接口
同 List 一样,Hprose 提供的所有 Map 类也都是通过接口来存取的,它们都实现了 IMap
接口。
IMap
接口中定义了枚举器操作,因此,在 Delphi 2005 以上或 FreePascal 2.5.1 以上版本中,您可以通过 for...in
语句来操作 IMap
接口的对象。枚举的元素类型为 TMapEntry
,该类型是一个记录体,它有 2 个元素:Key
和 Value
,这两个元素都是 Variant
类型的。
IMap
接口上定义了添加(Put
、PutAll
),获取(Get
),查找(ContainsKey
、ContainsValue
),删除(Delete
),清空(Clear
),复制(Assign
),同步(Lock
、UnLock
)等操作。
IMap
接口还定义了直接通过键值返回元素值的默认属性,可以让您向操作数组一样存取元素值,还定义了通过元素值获取键值的索引属性(Key
)。另外,它还定义了元素个数(Count
)、所有键值(Keys
)和所有元素值(Values
)这三个属性。
其定义如下:
IMap = interface(IReadWriteSync)
['{28B78387-CB07-4C28-B642-09716DAA2170}']
procedure Assign(const Source: IMap);
function GetCount: Integer;
function GetKeys: IImmutableList;
function GetValues: IImmutableList;
function GetKey(const AValue: Variant): Variant;
function GetValue(const AKey: Variant): Variant;
procedure PutValue(const AKey: Variant; AValue: Variant);
function Get(const AKey: Variant): Variant; overload;
function Get(const AKey: Variant; out AValue: Variant): Boolean; overload;
procedure Put(const AKey, AValue: Variant); overload;
procedure Put(const AList: IImmutableList); overload;
procedure Put(const AMap: IMap); overload;
procedure Put(const Container: Variant); overload;
procedure Put(const ConstArray: array of const); overload;
function Add(const AKey, AValue: Variant): Boolean;
procedure Clear;
function CompareKey(const Entry1, Entry2: TMapEntry): Integer;
function CompareValue(const Entry1, Entry2: TMapEntry): Integer;
function ContainsKey(const AKey: Variant): Boolean;
function ContainsValue(const AValue: Variant): Boolean;
function Delete(const AKey: Variant): Variant;
function GetEnumerator: IMapEnumerator;
function Join(const ItemGlue: string = ';';
const KeyValueGlue: string = '=';
const LeftPad: string = '';
const RightPad: string = ''): string;
procedure InitLock;
procedure InitReadWriteLock;
procedure Lock;
procedure Unlock;
procedure PutAll(const AList: IImmutableList); overload;
procedure PutAll(const AMap: IMap); overload;
procedure PutAll(const Container: Variant); overload;
procedure PutAll(const ConstArray: array of const); overload;
function ToList(ListClass: TListClass; Sync: Boolean = True;
ReadWriteSync: Boolean = False): IList;
function ToArrayList(Sync: Boolean = True;
ReadWriteSync: Boolean = False): IArrayList;
procedure Sort; overload;
procedure Sort(CompareProc: TMapCompareMethod); overload;
procedure SortByValue;
procedure TrimExcess;
property Count: Integer read GetCount;
property Key[const AValue: Variant]: Variant read GetKey;
property Value[const AKey: Variant]: Variant read GetValue write PutValue; default;
property Keys: IImmutableList read GetKeys;
property Values: IImmutableList read GetValues;
end;
后面我们会在介绍具体实现类的时候来详细讲解这些操作。
TAbstractMap 类
该类是所有可变类型 Map 的基类,它实现了 IMap
接口上的枚举器,复制和同步操作。它继承自 TInterfacedObject
,因此它也继承了接口生存周期管理。它是一个抽象类,您不应该对它进行实例化。
如果您打算实现自己的可变类型 Map,那么您应该直接或间接的继承自它。因为在 Hprose 序列化和反序列化时,判断一个类是否是可变类型的 Map 是通过判断 TAbstractMap
是否是这个类的祖先类的方式完成的。
该类上还实现了一个类方法 Split
。但因为 TAbstractMap
是抽象类,所以您只能在它的可实例化子类上调用它。该方法的具体用法,我们在下面介绍 THashMap
类时来详细介绍。
IHashMap 接口
IHashMap = interface(IMap)
['{B66C3C4F-3FBB-41FF-B0FA-5E73D87CBE56}']
end;
该接口继承自 IMap
接口,并且没有添加任何操作。你可能会觉得这样定义比较奇怪,因为在平时使用时,该接口似乎是没有什么用处的。
这样做的原因是为了在反序列化列表类型数据时,可以通过指定该具体的接口,来反序列化为具体的实现类对象。
IHashMap
接口对应 THashMap
实现。
IHashedMap
接口对应 THashedMap
实现。
ICaseInsensitiveHashMap
接口对应 TCaseInsensitiveHashMap
实现。
ICaseInsensitiveHashedMap
接口对应 TCaseInsensitiveHashedMap
实现。
如果反序列化时,指定的类型是 IMap
接口类型,那么反序列化时,也会反序列化为 THashMap
实现的具体对象。
关于序列化和反序列化的内容,我们会在后面具体的章节中在详细介绍。
THashMap 类
该类直接继承自 TAbstractMap
,它是最常用的 Map。与其它语言中的 HashMap
不同,它的 Hash 存取是基于 THashedList
实现的,因此它不但可以高速存取数据,还可以保持数据插入的顺序。
创建 THashMap 对象
THashMap
有多个构造方法,其中一部分继承自 TAbstractMap
:
constructor Create(ACapacity: Integer = 16; Factor: Single = 0.75; Sync: Boolean = True; ReadWriteSync: Boolean = False); overload; override;
constructor Create(ACapacity: Integer; Sync: Boolean; ReadWriteSync: Boolean = False); overload; virtual;
constructor Create(Sync: Boolean; ReadWriteSync: Boolean = False); overload; virtual;
constructor Create(const AList: IImmutableList; Sync: Boolean = True; ReadWriteSync: Boolean = False); overload; virtual;
constructor Create(const AMap: IMap; Sync: Boolean = True; ReadWriteSync: Boolean = False); overload; virtual;
constructor Create(const Container: Variant; Sync: Boolean = True; ReadWriteSync: Boolean = False); overload; virtual;
constructor Create(const ConstArray: array of const; Sync: Boolean = True; ReadWriteSync: Boolean = False); overload; virtual;
构造方法中的 ACapacity
参数表示初始化容量,如果您事先确知要放入的元素个数,那么将容量设置为与元素个数相同或多于元素个数,可以避免后面放入元素时内存的重新分配。默认初始化容量为 16。
初始化容量不代表这个 Map 只能放多少个元素,也不代表这个 Map 有多少个元素。它只代表在不重新分配内存的情况下,能放入的元素个数。当元素个数增长到超过这个容量时,这个容量会自动扩大,您不需要做任何特殊操作。
另一个参数是负载因子 Factor
,其默认值为 0.75,这是时间和空间成本上一种折衷:减小负载因子可以减少 Hash 表所占用的内存空间,但会增加查询数据的时间开销;增加负载因子会提高数据查询的性能,但会增加 Hash 表所占用的内存空间。所以,通常不需要改变这个默认值。