面试题答案
一键面试1. C++ 多态在策略模式中的关键作用
策略模式定义了一系列算法,将每个算法封装起来,使它们可以相互替换。在策略模式中,C++ 多态起到了核心作用,主要体现在以下方面:
- 解耦算法与使用算法的上下文:通过定义一个抽象的策略基类,具体的策略类继承自该基类并实现各自的算法。上下文类持有一个指向策略基类的指针或引用。这样,上下文与具体策略实现分离,只依赖于抽象策略接口,通过多态机制调用不同具体策略的方法。例如:
// 抽象策略类
class Strategy {
public:
virtual void execute() = 0;
virtual ~Strategy() = default;
};
// 具体策略类A
class ConcreteStrategyA : public Strategy {
public:
void execute() override {
std::cout << "Executing Strategy A" << std::endl;
}
};
// 具体策略类B
class ConcreteStrategyB : public Strategy {
public:
void execute() override {
std::cout << "Executing Strategy B" << std::endl;
}
};
// 上下文类
class Context {
private:
Strategy* strategy;
public:
Context(Strategy* s) : strategy(s) {}
~Context() { delete strategy; }
void doWork() {
strategy->execute();
}
};
这里,Context
类通过 Strategy
指针实现了对不同具体策略的调用,而无需关心具体是哪个策略,实现了算法与上下文的解耦。
2. 实现更灵活的动态策略切换
设计思路
为了实现动态策略切换,需要提供一种机制,让上下文在运行时能够改变其所持有的策略对象。可以通过提供一个接口,允许在运行时设置新的策略。
代码实现
// 抽象策略类
class Strategy {
public:
virtual void execute() = 0;
virtual ~Strategy() = default;
};
// 具体策略类A
class ConcreteStrategyA : public Strategy {
public:
void execute() override {
std::cout << "Executing Strategy A" << std::endl;
}
};
// 具体策略类B
class ConcreteStrategyB : public Strategy {
public:
void execute() override {
std::cout << "Executing Strategy B" << std::endl;
}
};
// 上下文类
class Context {
private:
Strategy* strategy;
public:
Context(Strategy* s) : strategy(s) {}
~Context() { delete strategy; }
void doWork() {
strategy->execute();
}
void setStrategy(Strategy* newStrategy) {
delete strategy;
strategy = newStrategy;
}
};
在 main
函数中可以这样使用:
#include <iostream>
int main() {
Strategy* strategyA = new ConcreteStrategyA();
Context context(strategyA);
context.doWork();
Strategy* strategyB = new ConcreteStrategyB();
context.setStrategy(strategyB);
context.doWork();
delete strategyB;
return 0;
}
这样,Context
类的对象在运行时可以切换不同的策略。
3. 潜在问题及解决方案
潜在问题
- 内存管理问题:在动态切换策略时,如果不妥善管理内存,可能会导致内存泄漏。例如,在
Context
类的setStrategy
方法中,如果没有先释放旧的策略对象,就会造成内存泄漏。 - 增加复杂性:随着策略数量的增加,代码的维护和理解难度可能会增大。每个具体策略类都需要正确实现抽象策略类的接口,否则可能导致运行时错误。
解决方案
- 内存管理:可以使用智能指针来管理策略对象的生命周期,从而避免手动内存管理带来的问题。例如,将
Context
类中的Strategy*
改为std::unique_ptr<Strategy>
:
// 上下文类
class Context {
private:
std::unique_ptr<Strategy> strategy;
public:
Context(std::unique_ptr<Strategy> s) : strategy(std::move(s)) {}
void doWork() {
strategy->execute();
}
void setStrategy(std::unique_ptr<Strategy> newStrategy) {
strategy = std::move(newStrategy);
}
};
这样,智能指针会自动处理对象的销毁,避免内存泄漏。
- 代码维护:为了降低代码复杂性,可以通过良好的文档注释、命名规范以及合理的代码组织结构来提高代码的可维护性。例如,将相关的策略类放在同一个命名空间或模块中,并为每个策略类提供清晰的功能说明。同时,可以通过单元测试确保每个策略类的正确性。