策略模式简述
在实际应用中,时常会遇到需要运行时判断执行具体算法的场景。这个时候,使用多个if else判断会让我们的代码显得很臃肿,灵活运用哈希表和策略模式会减少核心业务逻辑代码的规模,提高其可读性和可扩展性。
示例:分享给朋友功能
举个最常见的栗子,有篇文章写的很好,想分享给朋友,通常会出现多个选项:分享至微信好友,QQ好友,朋友圈等。简化的代码示意如下:
void share(const std::string& content, const std::string& shareType) {
if (shareType == "wechat") {
// 分享给微信好友
} else if (shareType == "qq") {
// 分享给QQ好友
} else if ...
}
可以看出,这种实现方法的弊端在于:如果有多种社交软件,我们需要多行if else代码来判断。更可怕的是,如果将来新增或删除一种分享方式,需要深入到这个代码块去一个个找if statement做修改。
策略模式的实现
使用策略模式时,我们首先要抽象出一个通用的接口,也就是share。对于每一种社交软件,我们都实现一次这个接口,分别执行不同的任务。C++代码如下:
通用策略接口:
struct ShareStrategy {
virtual void share(const std::string &content) = 0;
};
分享至微信好友策略:
struct WechatShareStrategy : ShareStrategy {
void share(const std::string &content) override {
std::cout << "Sharing to Wechat friend: " << content << std::endl;
}
};
分享至QQ好友策略:
struct QQShareStrategy : ShareStrategy {
void share(const std::string &content) override {
std::cout << "Sharing to QQ friend: " << content << std::endl;
}
};
用户类(Context)调用实现:
class User {
public:
explicit User(std::shared_ptr<ShareStrategy> shareStrategy = nullptr) : shareStrategy(shareStrategy) {
// 初始化哈希表
strategyMapper = {{"qq", std::make_shared<QQShareStrategy>()},
{"wechat", std::make_shared<WechatShareStrategy>()}};
}
// 分享功能,调用策略对象所封装的方法
void share(const std::string &content) {
// 曾经的if else在这里,现在只需要一行
shareStrategy->share(content);
}
// 根据用户输入,查表选择应该调用的策略
void resolveShareStrategy(const std::string &pattern) {
shareStrategy = strategyMapper[pattern];
}
private:
// 当前所选择的策略
std::shared_ptr<ShareStrategy> shareStrategy;
// 存一个哈希表,用于根据用户输入而动态选择策略
std::map<std::string, std::shared_ptr<ShareStrategy>> strategyMapper;
};
Demo用例实现:
用一个tuple来模拟用户请求,两个字段分别代表分享方法和内容。
int main() {
User user;
// C++17 structured binding
const auto&[shareType, content] = std::tuple<std::string, std::string>{
"wechat",
"Have a nice day."
};
// 确定分享策略
user.resolveShareStrategy(shareType);
// 分享内容
user.share(content);
// 改变一次分享策略
user.resolveShareStrategy("qq");
// 分享内容
user.share(content);
}
输出
Sharing to Wechat friend: Have a nice day.
Sharing to QQ friend: Have a nice day.
结语
策略模式的好处在于扩展性良好,便于维护。想删除一个策略时只需要去除其实现类即可,而不再需要在茫茫if else海中寻找代码。同样地,想添加一个策略,也不需要在用户类的代码里寻找相应的方法。
其实,虽然看上去我们的核心业务代码少了很多if else,代码更清晰简洁。但也在无形中增添了很多策略的实现类。该少的代码一行少不了,只是换了个地方而已。所以,具体应该如何选择还是应该视核心代码的规模和策略的数量而定。