-
Notifications
You must be signed in to change notification settings - Fork 36
可变类型的 Map
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 |
+------------+ +------------+ +---------------------------+
同 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;
后面我们会在介绍具体实现类的时候来详细讲解这些操作。
该类是所有可变类型 Map 的基类,它实现了 IMap
接口上的枚举器,复制和同步操作。它继承自 TInterfacedObject
,因此它也继承了接口生存周期管理。它是一个抽象类,您不应该对它进行实例化。
如果您打算实现自己的可变类型 Map,那么您应该直接或间接的继承自它。因为在 Hprose 序列化和反序列化时,判断一个类是否是可变类型的 Map 是通过判断 TAbstractMap
是否是这个类的祖先类的方式完成的。
该类上还实现了一个类方法 Split
。但因为 TAbstractMap
是抽象类,所以您只能在它的可实例化子类上调用它。该方法的具体用法,我们在下面介绍 THashMap
类时来详细介绍。
IHashMap = interface(IMap)
['{B66C3C4F-3FBB-41FF-B0FA-5E73D87CBE56}']
end;
该接口继承自 IMap
接口,并且没有添加任何操作。你可能会觉得这样定义比较奇怪,因为在平时使用时,该接口似乎是没有什么用处的。
这样做的原因是为了在反序列化列表类型数据时,可以通过指定该具体的接口,来反序列化为具体的实现类对象。
IHashMap
接口对应 THashMap
实现。
IHashedMap
接口对应 THashedMap
实现。
ICaseInsensitiveHashMap
接口对应 TCaseInsensitiveHashMap
实现。
ICaseInsensitiveHashedMap
接口对应 TCaseInsensitiveHashedMap
实现。
如果反序列化时,指定的类型是 IMap
接口类型,那么反序列化时,也会反序列化为 THashMap
实现的具体对象。
关于序列化和反序列化的内容,我们会在后面具体的章节中在详细介绍。
该类直接继承自 TAbstractMap
,它是最常用的 Map。与其它语言中的 HashMap
不同,它的 Hash 存取是基于 THashedList
实现的,因此它不但可以高速存取数据,还可以保持数据插入的顺序。
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 表所占用的内存空间。所以,通常不需要改变这个默认值。