程序在运行的过程中,经常需要改变一些对象的属性值,例如改变某个对话框的横坐标。这一般是通过调用该对象的某个特定方法实现的,以改变对话框横坐标为例,这个方法可能是CGUIDialog::SetX()。
CEGUI将这种属性操作进行了提炼,在上层形成了一个公共的接口,以统一的方式处理所有属性,为其它一些功能,例如动画功能打下了基础。
属性系统类图如下
各种不同的属性类派生自Property类,该类有两个虚方法,get()和set(),负责属性的读取和存储。每种Property在程序中只有唯一一个静态对象,它并不保存所谓的属性值,它只是一个代理者。以set方法为例,它的完整签名是
Property::set(PropertyReceiver* receiver, const String&value)
该方法将receive转换为某种对象指针,然后以value为参数调用该种对象的某个方法,一种Property就对应一种特定的对象和它的一个特定的方法。以Alpha为例,它对应Window类和它的set/getAlpha方法,它的set方法完整代码如下
void Alpha::set(PropertyReceiver* receiver, const String& value)
{
static_cast<Window*>(receiver)->setAlpha(PropertyHelper::stringToFloat(value));
}
属性系统的时序图如下
CEGUI属性系统的优点是抽象层次很高,以统一的方式处理所有属性,但缺点就是效率,因为它需要将具体数值类型和string进行相互转换,我曾经想把Property的虚方法进行扩充,增加set/getInt这样的方法,这样做就可以避免具体数值类型和string之间的转换。但如果这样做,那么属性类型的抽象就没有了,所有依赖属性类型抽象的地方都必然会形成巨大的switch-case或者类似的东西,这会让人很恶心,所以还是算了。
不过属性系统还是有可以优化的地方的:mapNameAndProperty不是指针,每个PropertySet对象都有一份它的实例,而相同类型的PropertySet对象,例如所有Window对象,它们的mapNameAndProperty的是一模一样的,所以我觉得可以把mapNameAndProperty改为指针引用,而真正的实例作为静态变量存储在相应的类中,类图如下:
在某种PropertySet类第一次构造对象的时候,填充这个属性map,并在构造函数中把PropertSet::pMapNameAndProperty指向它,这样可以省一些空间。