使用 SOUI 对象属性的别名¶
许多开发者反馈 SOUI 的对象属性命名不符合日常开发习惯。为了解决这个问题,从 SOUI 5.0.0.3 版本开始,提供了属性别名功能,允许开发者将自定义的属性名映射到 SOUI 对象的内建属性。
属性别名机制介绍¶
属性别名机制允许开发者在 XML 布局文件或代码中使用自定义的属性名,而这些别名会在运行时自动转换为 SOUI 框架内部的标准属性名。这种方式不仅提高了代码的可读性,还增强了属性命名的灵活性。
核心接口¶
IAttrAlias 接口¶
IAttrAlias 是属性别名功能的核心接口,用于定义属性名的映射关系:
SNSBEGIN
#undef INTERFACE
#define INTERFACE IAttrAlias
DECLARE_INTERFACE_(IAttrAlias, IObjRef)
{
/**
* @brief 增加引用计数
* @return 新的引用计数
*/
STDMETHOD_(long, AddRef)(THIS) PURE;
/**
* @brief 减少引用计数
* @return 新的引用计数
*/
STDMETHOD_(long, Release)(THIS) PURE;
/**
* @brief 当引用计数为零时调用,用于对象释放前的清理工作
*/
STDMETHOD_(void, OnFinalRelease)(THIS) PURE;
//-----------------------------------------------------------------------------------
/**
* @brief 获取属性别名
* @param pszAttr -- 属性名(代码中使用的自定义属性名)
* @param pszClsName -- 对象类名
* @param objType -- 对象类型
* @return LPCWSTR SOUI 内建属性名
*/
STDMETHOD_(LPCWSTR, GetAttrAlias)(CTHIS_ LPCWSTR pszAttr, LPCWSTR pszClsName, int objType) SCONST PURE;
};
SNSEND
GetAttrAlias 方法详解¶
GetAttrAlias
方法是属性别名转换的核心,它接收以下参数: - pszAttr
:代码中调用 SetAttribute 时传入的自定义属性名 - pszClsName
:对象的类名 - objType
:对象类型
该方法返回指向 SOUI 对象内建属性名的常量指针。
IApplication 接口扩展¶
为了支持属性别名功能,IApplication 接口中新增了两个方法:
SNSBEGIN
DECLARE_INTERFACE_(IApplication, IObjRef){
/**
* @brief 设置属性别名获取接口
* @param pAttrAlias IAttrAlias* -- 属性别名接口
* @return void
*/
STDMETHOD_(void, SetAttrAlias)(THIS_ IAttrAlias * pAttrAlias) PURE;
/**
* @brief 获取属性别名接口
* @return const IAttrAlias* -- 属性别名接口
*/
STDMETHOD_(const IAttrAlias *, GetAttrAlias)(CTHIS) SCONST PURE;
/**
* @brief 获取对象的基类名称
* @param pszClassName LPCWSTR -- 对象类名
* @param objType int -- 对象类型
* @param pszBaseClassName[MAX_OBJNAME] wchar_t -- 基类名称
* @return BOOL -- TRUE: 成功
*/
STDMETHOD_(BOOL, GetBaseClassName)(CTHIS_ LPCWSTR pszClassName, int objType, wchar_t pszBaseClassName[MAX_OBJNAME]) SCONST PURE;
};
SNSEND
工作原理¶
当调用 IObject 的 SetAttribute 方法设置属性值时,系统会执行以下步骤:
- 通过
IApplication::GetAttrAlias
方法获取属性别名接口 - 调用
IAttrAlias::GetAttrAlias
方法将自定义属性名转换为内建属性名 - 将转换后的属性名和属性值传入对象的 SetAttribute 方法中
如果没有设置属性别名接口,IAttrAlias::GetAttrAlias
方法会直接返回传入的属性名,即不进行任何转换。
应用场景¶
属性别名功能可以应用于以下场景:
- 提高代码可读性:使用更符合团队命名规范的属性名
- 保持兼容性:在不修改现有代码的情况下,统一属性命名风格
- 属性加密:通过自定义别名实现 XML 文件中属性名称的加密,增强保密性
使用示例¶
以 Window 类为例,其内建属性包括 colorBkgnd
、colorBorder
、colorText
等。这些命名可能不符合某些团队的命名规范,可以通过属性别名功能将其重命名为更通用的名称。
实现属性别名接口¶
#include <helper/sobj-ref-impl.hpp>
class CAttrAliasImpl : public TObjRefImpl<IAttrAlias>
{
public:
STDMETHOD_(LPCWSTR, GetAttrAlias)(CTHIS_ LPCWSTR pszAttr, LPCWSTR pszClsName, int objType) SCONST
{
// 注意:pszAttr 是你自定义的属性名,返回的是框架中已有的属性名
if(objType == WINDOW)
{
if(wcscmp(pszAttr, L"bkcolor") == 0)
{
return L"colorBkgnd";
}
else if(wcscmp(pszAttr, L"bordercolor") == 0)
{
return L"colorBorder";
}
else if(wcscmp(pszAttr, L"textcolor") == 0)
{
return L"colorText";
}
}
// 如果没有匹配的别名,返回原始属性名
return pszAttr;
}
};
注册属性别名接口¶
在应用程序初始化时注册属性别名接口:
int main()
{
SApplication app;
// 创建并注册属性别名接口
CAttrAliasImpl * pAttrAlias = new CAttrAliasImpl;
app.SetAttrAlias(pAttrAlias);
pAttrAlias->Release();
app.Run();
return 0;
}
使用效果¶
配置完成后,可以在 XML 布局文件或代码中使用自定义属性名:
// 使用自定义属性名
SetAttribute(L"bkcolor", L"#ffffff");
// 仍然可以使用原始属性名
SetAttribute(L"colorBkgnd", L"#ffffff");
在 XML 布局文件中:
<!-- 使用自定义属性名 -->
<window bkcolor="#ffffff" bordercolor="#000000" textcolor="#333333"/>
<!-- 仍然可以使用原始属性名 -->
<window colorBkgnd="#ffffff" colorBorder="#000000" colorText="#333333"/>
最佳实践¶
- 统一命名规范:在团队内部统一属性命名规范,提高代码一致性
- 完整映射:为常用属性提供完整的别名映射,避免混用
- 文档记录:维护属性别名映射表,方便团队成员查阅
- 向后兼容:保持对原始属性名的支持,确保现有代码的兼容性
- 性能考虑:属性别名转换会带来轻微的性能开销,应避免在高频调用场景中使用
通过合理使用属性别名功能,可以显著提升 SOUI 应用的开发体验和代码可维护性。