如果你使用 Qt 开发应用程序, 那你一定写过下面的代码
// main.cpp
int main(int argc, char** argv)
{
QApplication a(argc, argv);
MyWidget myWidget;
myWidget.show();
return a.exec();
}
这段代码相当直接: 创建一个 QApplication
对象、 创建一个窗体、显示窗体、执行事件循环。 如果你在开发一个小工具,这样的代码是完全没有问题的。
但是, 随着软件规模的扩大, 我们需要引入更多的模块。 比如注册 CrashHandler、初始化程序的其他模块、检查加密狗、初始化内存池等操作。 这样一来,在main
函数里就要写许多代码, 而且接盘的新程序员要花很多时间搞清楚“CrashHandler 是在哪行注册的来着?”这种问题。
为了清楚地指出初始化顺序,需要对应用程序的启动流程进行管理, 这里我给出一套最基本的框架。
class BootRoutain
{
using Self = BootRoutain;
public:
BootRoutain(int argc, char** argv)
: app(argc, argv)
{}
protected:
virtual void beforeBoot() {};
virtual void onBoot() {};
virtual void afterBoot() {};
public:
int exec()
{
Self::beforeBoot();
Self::onBoot();
Self::afterBoot();
return app.exec();
}
private:
QApplication app;
};
首先, 把应用程序的启动流程分为3个阶段: 启动前, 启动中, 启动后。 模块初始化等工作放在启动前, 窗口的显示放在启动中, 而启动过程中资源的销毁放在启动后。
class BootLifeTime : public BootRoutain
{
public:
BootLifeTime(int argc, char** argv)
: BootRoutain(argc, argv)
{
}
protected:
virtual void beforeBoot() override
{
// 初始化窗口
widget.setWindowTitle("Hello");
widget.resize(800, 600);
}
virtual void onBoot() override
{
widget.show();
}
// 如果要清理某些资源, 就 override afterBoot();
private:
QWidget widget;
};
在派生类中, 实现具体的启动逻辑。
int main(int argc, char** argv)
{
BootLifeTime bootLifeTime(argc, argv);
return bootLifeTime.exec();
}
最后在main()
中实例化这个对象并调用exec()
函数。 启动的整个流程变得非常清晰。