我将尝试通过我目前正在开发的应用程序来解释我的困惑。
我的应用程序(基于 Qt5.1 + Qt Quick Controls)与 Facebook API 交互以管理 Facebook 页面。我试图将 QML 代码(用于 UI)与 C++ 核心尽可能分开。
现在,需要 OAuth2 实现才能与 Facebook API 交互。为此,我有一个 C++ OAuth2 类,其构造函数具有以下签名:
OAuth2::OAuth2(QString appId, QString redirectUrl, QStringList 权限);
现在,由于 OAuth 过程需要一个浏览器,我还实现了一个 OAuthBrowser.qml,它使用 OAuth2 来完成授权。
我有以下选项可以将 OAuth2 类公开给 OAuth2Browser:
- 实例化 OAuth2 并使用 setContextProperty() 将实例公开给 OAuth2Browser。但是,这意味着我的 C++ 代码必须处理 UI 代码。更令人费解的问题是 OAuth2Browser 是一个辅助窗口。当用户单击 MainWindow 上的“授权”窗口时,
AppController C++ 对象(连接到 MainWindow)将启动 OAuth2Browser 窗口。因此,OAuth2Browser 的实例化代码将深入到 AppController 方法中。如果只有 main.cpp 必须处理窗口创建,那就太好了。 - 使用 qmlRegisterType()。在这种情况下,我无法将参数传递给构造函数。所以,我必须实现一个初始化 OAuth2 对象的 init() 方法。然后,我会在 OAuth2Browser 的 Component.onCompleted() 方法中调用这个 init() 方法。但是,在这种方法中,我必须将 QSettings 暴露给 UI 代码 - QML 窗口,以便 init() 方法所需的参数可以被取回。我非常怀疑将应用程序设置直接暴露给 QML UI 是否是一个好主意。
- 在 OAuth2 构造函数中隐式使用 QSettings。这样,我就不必传递任何参数,并且可以使用 qmlRegisterType()。然而,这意味着我正在“幕后”做一些神奇的事情。我没有显式传递 QSettings 实例,而是在任何我想使用的地方使用它,从而对公共 API 隐藏了初始化细节。
在 IRC 上建议了基于第三个选项的替代方案 - 如果没有将参数传递给构造函数,则使用 initFromSettings() 类型的方法来初始化实例。这样,初始化不会被隐藏,并且 initFromSettings() 可以自信地在其内部使用 QSettings。现在,我可以愉快地使用 qmlRegisterType() 在 QML 中实例化 OAuth2。
那么,更好的方法是什么?
还,
- 将 QSettings 直接暴露给 QML UI 是个好主意吗?
- 我个人更喜欢 qmlRegisterType() 到 setContextProperty() - 这样,注册类实例的生命周期仅由 QML 维护。但是,由于缺乏对参数化构造函数的支持,前者不太可能使用,除非
显式使用某种形式的 init() 进行初始化。这是一个好的设计吗?
我提前为一篇冗长的帖子道歉。但我认为最好在这里问。