Skip to content

使用 SOUI 对象属性的别名

Warning

The current page still doesn't have a translation for this language.

You can read it through google translate.

许多开发者反馈 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 方法设置属性值时,系统会执行以下步骤:

  1. 通过 IApplication::GetAttrAlias 方法获取属性别名接口
  2. 调用 IAttrAlias::GetAttrAlias 方法将自定义属性名转换为内建属性名
  3. 将转换后的属性名和属性值传入对象的 SetAttribute 方法中

如果没有设置属性别名接口,IAttrAlias::GetAttrAlias 方法会直接返回传入的属性名,即不进行任何转换。

应用场景

属性别名功能可以应用于以下场景:

  1. 提高代码可读性:使用更符合团队命名规范的属性名
  2. 保持兼容性:在不修改现有代码的情况下,统一属性命名风格
  3. 属性加密:通过自定义别名实现 XML 文件中属性名称的加密,增强保密性

使用示例

以 Window 类为例,其内建属性包括 colorBkgndcolorBordercolorText 等。这些命名可能不符合某些团队的命名规范,可以通过属性别名功能将其重命名为更通用的名称。

实现属性别名接口

#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"/>

最佳实践

  1. 统一命名规范:在团队内部统一属性命名规范,提高代码一致性
  2. 完整映射:为常用属性提供完整的别名映射,避免混用
  3. 文档记录:维护属性别名映射表,方便团队成员查阅
  4. 向后兼容:保持对原始属性名的支持,确保现有代码的兼容性
  5. 性能考虑:属性别名转换会带来轻微的性能开销,应避免在高频调用场景中使用

通过合理使用属性别名功能,可以显著提升 SOUI 应用的开发体验和代码可维护性。