面试题答案
一键面试1. 单例模式替代全局变量
- 原理:单例模式确保一个类只有一个实例,并提供一个全局访问点。相比全局变量,单例模式可以更好地控制实例的创建和访问,提高代码的可维护性。
- 示例:
class GlobalSettings {
public:
static GlobalSettings& getInstance() {
static GlobalSettings instance;
return instance;
}
int getSomeValue() const { return someValue; }
void setSomeValue(int value) { someValue = value; }
private:
int someValue;
GlobalSettings() : someValue(0) {}
~GlobalSettings() = default;
GlobalSettings(const GlobalSettings&) = delete;
GlobalSettings& operator=(const GlobalSettings&) = delete;
};
各模块通过 GlobalSettings::getInstance().getSomeValue()
来访问设置,避免了直接使用全局变量。
2. 依赖注入
- 原理:将依赖的对象(原本可能是全局变量)通过参数传递给需要使用它的模块,而不是让模块自行获取全局变量。这样可以降低模块间的耦合度,提高模块的可测试性。
- 示例:
class Module {
public:
Module(int& globalVar) : globalVar(globalVar) {}
void doSomething() {
// 使用 globalVar
}
private:
int& globalVar;
};
在调用模块时,将相关变量传递进去:
int main() {
int globalValue = 10;
Module module(globalValue);
module.doSomething();
return 0;
}
3. 命名空间隔离
- 原理:将全局变量按照功能划分到不同的命名空间中,避免命名冲突,同时也使代码结构更加清晰。
- 示例:
namespace Graphics {
int screenWidth;
int screenHeight;
}
namespace Physics {
float gravity;
}
模块在使用时明确指定命名空间,如 Graphics::screenWidth
。
4. 封装全局变量访问
- 原理:为全局变量提供一组访问函数,模块通过这些函数来操作全局变量,而不是直接访问。这样可以在访问函数中添加逻辑控制,如数据验证、日志记录等。
- 示例:
int globalCounter;
void incrementGlobalCounter() {
globalCounter++;
// 可以在此处添加日志记录
}
int getGlobalCounter() {
return globalCounter;
}
模块通过调用 incrementGlobalCounter()
和 getGlobalCounter()
来操作全局变量。
5. 分层架构
- 原理:将项目分为不同的层次,如数据访问层、业务逻辑层、表示层等。全局变量尽量放在较低层次,并通过接口向上层提供服务,减少上层对全局变量的直接依赖。
- 示例:在数据访问层管理数据库连接的全局变量,业务逻辑层通过数据访问层提供的接口来操作数据库,而不是直接访问数据库连接变量。这样如果数据库连接方式改变,只需要在数据访问层修改,不会影响到业务逻辑层和表示层。