关联对象,按字面理解 无非就是将两个对象关联起来。'关联'可以联想到映射,能完成这件事情的,首先想到的数据结构就是hash_map。事实上objc_runtime就是这么做的。
有了思路,我们就可以自己动手了。思路大概是这样的,我们现在要实现为一个对象去关联多个对象,这些多个对象通过不同的KEY值来存取。这样的话,一张hash表似乎是不行的。一张表只能完成一个对象到一个对象的映射。如果思路受阻,请默念下面这段话三次。
All problems in computer science can be solved by another level of indirection,
except of course for the problem of too many indirections.
一张表不行,我们可以维护这样一张表,他将每个对象映射到一张表,而映射到的表分别将不同的KEY映射到不同的对象。这样就实现了将一个对象通过不同的KEY关联到另一个对象。这里涉及 TARGET(被关联的对象) KEY(键) OBJECT(关联对象)。
typedef long TARGET;
typedef long KEY;
typedef long OBJECT;
这里全都用了long型,为什么用long型呢?(这里似乎是应该用 void *更合理嘛)。因为c++库中的hash_map需要提供两个函数对象 ,分别用来比较KEY值大小和计算KEY的哈希值(方便在hash_map中储存自定义类型)。而long型是基本类型,省去了这样的麻烦。另外就是long 在计算机中是8字节,现在大部分pc都是64位,指针也是8字节,内存模型匹配,我们可以通过类型转换来处理这个问题。是不是很讨巧呢。
typedef hash_map<TARGET,hash_map<KEY,OBJECT> > MAP;
typedef hash_map<KEY,OBJECT> ASSOCIATION_MAP;
我们将总表的类型定义为MAP,而具体的KEY->OBJECT的映射表定义为ASSOCIATION_MAP;
好了,话不多说,直接看代码,相当简单的代码:
#include <iostream>
#include <map>
#include <ext/hash_map>
using __gnu_cxx::hash_map;
using __gnu_cxx::pair;
typedef long TARGET;
typedef long KEY;
typedef long OBJECT;
typedef hash_map<TARGET,hash_map<KEY,OBJECT> > MAP;
typedef hash_map<KEY,OBJECT> ASSOCIATION_MAP;
typedef pair<TARGET,hash_map<KEY,OBJECT>> TARGET_ASSOCIATIONMAP;
typedef pair<KEY,OBJECT> KEY_OBJECT;
class AssociationManager
{
public:
static MAP & manager()
{
return AssociationManager::association;
}
private:
static MAP association;
private:
AssociationManager ()
{
}
};
MAP AssociationManager::association = MAP();
OBJECT getAssociated(TARGET target,KEY key)
{
OBJECT result = 0;
MAP &map(AssociationManager::manager());
MAP::iterator it = map.find(target);
if(it != map.end())
{
ASSOCIATION_MAP &ass_map(it->second);
ASSOCIATION_MAP::iterator ass_map_it = ass_map.find(key);
if(ass_map_it != ass_map.end())
{
return ass_map_it->second;
}
}
return result;
}
void setAssociate(TARGET target,KEY key,OBJECT objc)
{
MAP &map(AssociationManager::manager());
MAP::iterator it = map.find(target);
if(it == map.end())
{
ASSOCIATION_MAP ass_map;
ass_map.insert(KEY_OBJECT(key,objc));
map.insert(TARGET_ASSOCIATIONMAP(target,ass_map));
}
else
{
(it->second).insert(KEY_OBJECT(key,objc));
}
}
class CTarget
{
public:
int index;
};
class CObject
{
public:
int number;
};
int main(int argc, const char * argv[]) {
CTarget * p_target = new CTarget;
p_target->index = 1;
CObject * p_object = new CObject;
p_object->number = 2;
static char key[10] = "hello_map";
// setAssociate
setAssociate((TARGET)p_target, (KEY)key, (OBJECT)p_object);
// getAssociated
CObject * p_obj = (CObject*)getAssociated((TARGET)p_target, (KEY)key);
// test
std::cout << "关联对象.number = "<<p_obj->number << std::endl;
std::cout << "Hello, World!\n";
return 0;
}
我们实现了两个函数getAssociated 和setAssociate,接着我们定义了两个类,在main函数中,我们通过两个函数将两个对象关联,并随后通过第一个对象成功取出关联的对象。为了只表达出思路,代码写的十分精简,点到为止。方便阅读。当然objc_runtime在实现的时候,还需要考虑到存取策略等一些列的问题。
网友评论