TinyMail研究—类型系统
转载时请注明出处和作者联系方式:http://blog.csdn.net/absurd
作者联系方式:李先静<xianjimli at hotmail dot com>
更新时间:2007-4-11
TinyMail是一套针对移动设备设计的邮件系统框架,为了达到最大的灵活性,它采用了很多设计模式和先进的编程技术,让框架的每一部分都可以定制和配置。TinyMail流行的趋势非常明显,Nokia770/800和GPE Phone Edition等项目中都使用了它。因为我们也要开发邮件系统,所以花了几天时间去研究它的实现,这里记录一些研究笔记,供有兴趣的朋友参考。本文介绍一下TinyMail的类型系统 。
TinyMail虽然是用C语言开发的,但完全采用了面向对象的设计方法,为此它实现了自己的类型系统。TinyMail的类型系统和glib的类型系统极为类似,让人奇怪的是,TinyMail本身已经使用了glib,为什么它不用gobject的类型系统,而要自己实现一套呢?抱着这个疑问,我花了一些时间去研究它的实现:
1. Object与ObjectClass。
和gobject一样,每个类都由两个基本结构组成:Object与ObjectClass。
Object结构定义了对象的数据成员,每个对象实例都有自己的拷贝。该结构的第一个成员用来实现继承关系,这是C语言中实现继承的常用手法。比如(CamelService继承于CamelObject):
struct _CamelService { CamelObject parent_object; struct _CamelServicePrivate *priv;
CamelSession *session; CamelProvider *provider; CamelServiceConnectionStatus status; CamelOperation *connect_op; CamelURL *url; gpointer data; }; |
ObjectClass定义了对象的行为和所有实例的共享数据。对象的行为也就是一些函数指针,用来实现虚函数。该结构的第一个成员用来实现继承关系,这是C语言中实现继承的常用手法。如(CamelServiceClass继承于CamelObjectClass):
typedef struct { CamelObjectClass parent_class;
void (*construct) (CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex);
gboolean (*connect) (CamelService *service, CamelException *ex); gboolean (*disconnect) (CamelService *service, gboolean clean, CamelException *ex); void (*cancel_connect) (CamelService *service);
GList * (*query_auth_types) (CamelService *service, CamelException *ex);
char * (*get_name) (CamelService *service, gboolean brief); char * (*get_path) (CamelService *service);
} CamelServiceClass; |
这与glib相似。
2. 类型的注册。
可以调用函数camel_type_register向类型系统注册新类型,注册时要提供下列信息:
l 父类的类型。
l 名称。
l Object的大小。
l ObjectClass的大小。
l ObjectClass的初始化函数。
l ObjectClass的释放函数。
l Object的初始化函数。
l Object的释放函数。
camel_interface_register是对camel_type_register的包装,用于注册接口。由于接口只有虚函数,没有数据成员,所以Object的大小为0,也没有Object的初始化函数和释放函数。
camel_type_register调用co_type_register完成注册。在注册时,co_type_register先建立类型的层次关系,然后插入到hash表中,最后调用ObjectClass的初始化函数。在调用ObjectClass的初始化函数时,它会从最顶层基类的ObjectClass的初始化函数一直调到当前类的ObjectClass的初始化函数。
这与glib相似。
3. 对象的创建。
可以调用camel_object_new创建对象实例,该函数要求一个指明对象类型的参数。也可以调用camel_object_new_name创建对象实例,该函数是对camel_object_new包装,它先通过类型名称获得类型,然后调用camel_object_new创建对象。
camel_object_new首先根据注册时指定的对象大小分配一块内存,然后调用Object的初始化函数初始化它,然后返回指向该内存块的指针。在调用Object的初始化函数时,它会从最顶层基类的Object的初始化函数一直调到当前类的Object的初始化函数。
这与glib相似。
4. 对象的销毁。
虽然在注册类型时,指定了Object的释放函数,但不直接调用它去销毁对象,而是由对象的引用计数来决定是否真正销毁对象。
camel_object_unref用于将对象的引用计数减一,当对象的引用计数为0时,它会:
l 触发finalize信号,让相关对象得到通知。
l 从当前类的Object的释放函数一直调到最顶层基类的Object的释放函数。
l 释放内存。
与glib相比,对象的销毁不再分dispose和finalize两阶段,对于互相引用的对象可能存在问题。
5. 对象的引用计数。
camel_object_ref增加引用计数。
camel_object_unref减少引用计数。
与glib相比,缺少弱引用(weak ref)功能,但可以通过finalize信号来模拟实现。
6. 对象的属性。
camel_object_set/camel_object_setv可以用来设置对象的属性。
camel_object_get/camel_object_getv/camel_object_get_ptr/camel_object_get_int可以用来获取对象的属性。
与glib相比,不需要安装属性的spec。
7. signal(event)机制。
camel_object_hook_event用于注册。
camel_object_remove_event/camel_object_unhook_event用于注销。
camel_object_trigger_event用于触发。
与glib相比,不需要那套复杂的marshal机制,所有参数都是gpointer格式,但使用简单的同时也失去类型检查的好处。
8. 持久化。
camel_object_state_write负责保存对象状态。
camel_object_state_read负责恢复对象状态。
与glib相比,这是一个特有的功能。
综上所述,我觉得TinyMail的类型系统虽然实现很精巧,但完全可以建立在glib的类型系统之上,没有必要自己重搞一套。
~~end~~