QT之策略模式【消除if else】
前言
策略模式即在运行时根据需求执行不同的方法。需要定义家族算法,通过多态重写同一个函数,可实现调用者的无感替换,不影响调用者。
策略模式把实现类和调用类实现了二者的分离,代码解耦。
策略模式提供了对开闭原则的完美支持。
策略模式依赖接口编程,同一接口支持多种实现方法。
一、策略模式基本实现
基类定义ExecTool方法,子类重写该方法,实现不同的功能逻辑。
class ToolBase : public QObject {
Q_OBJECT
public:
virtual bool ExecTool() { return true; }
};
定义子类工具A
class ToolA : public ToolBase {
Q_OBJECT
public:
bool ExecTool() override {
qDebug() << "ToolA";
return true;
}
};
定义子类工具B
class ToolB : public ToolBase {
Q_OBJECT
public:
bool ExecTool() override {
qDebug() << "ToolB";
return true;
}
};
根据策略执行不同的行为
int main(int argc, char *argv[])
{
ToolBase* p = nullptr;
QString str = "ToolA";
if (str == "ToolA") {
p = new ToolA();
} else {
p = new ToolB();
}
p->ExecTool();
return 0;
}
二、问题点
如果目前需要新增一种工具, if else处要增加一个判断。那如果100个工具呢,1000个工具呢,代码将会非常臃肿,维护成本急剧增加。
三、进阶
增加工具注册类ToolRegiser.h文件,利用模板、函数指针和hash实现,使用前需要先调用REGISTER_TYPE宏注册工具子类。
调用类main.cpp只需要根据类名或者key值,即可创建工具子类,不再需要if else逻辑判断,代码相当简洁。
工具注册类【ToolRegister.h】
#define REGISTER_TYPE(ClassName) ToolRegister::registerTool<ClassName>();
class ToolRegister {
public:
template <class T>
static void registerTool() {
creatorMap().insert(T::staticMetaObject.className(), &creatorHelper<T>);
}
static ToolBase* newInstance(const QString& className) {
if (Creator creator = creatorMap().value(className)) {
return (*creator)();
}
return nullptr;
}
private:
typedef ToolBase* (*Creator)();
template <typename T>
static ToolBase* creatorHelper() {
return new T();
}
static QMap<QString, Creator>& creatorMap() {
static QMap<QString, Creator> map;
return map;
}
};
调用类【main.cpp】
int main(int argc, char *argv[])
{
//注册类
REGISTER_TYPE(ToolA);
REGISTER_TYPE(ToolB);
QString str = "ToolA";
if (ToolBase* p = ToolRegister::newInstance(str)) {
p->ExecTool();
}
return 0;
}
总结
优化 => 枚举/字符串 + Hash + 函数指针 + 模板
如果大家在学习一个项目时,代码中有大量的if else判断,这可能由于设计之初没有考虑到业务需求的剧增,也可能随着维护时间越长,慢慢累积导致的。无论如何你应当重构这类代码,消除代码的坏味道,在日常编写代码的过程中即可完成代码重构。