策略(Strategy)模式定义
策略模式(Startegy):它定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。
策略(Strategy)模式优缺点
优点
- 可以在运行时切换对象内的算法。
- 可以将算法的实现和使用算法的代码隔离开来。
- 可以使用组合来代替继承。
- 开闭原则。你无需对上下文进行修改就能够引入新的策略。
缺点
- 如果你的算法极少发生改变,那么没有任何理由引入新的类和接口。使用该模式只会让程序过于复杂。
- 客户端必须知晓策略间的不同——它需要选择合适的策略。
- 许多现代编程语言支持函数类型功能,允许你在一组匿名函数中实现不同版本的算法。这样,你使用这些函数的方式就和使用策略对象时完全相同,无需借助额外的类和接口来保持代码简洁
策略(Strategy)模式构成与实现
构成
- 上下文(Context)维护指向具体策略的引用,且仅通过策略接口与该对象进行交流。
- 策略(Strategy)接口是所有具体策略的通用接口,它声明了一个上下文用于执行策略的方法。
- 具体策略(Concrete Strategies)实现了上下文所用算法的各种不同变体。
- 当上下文需要运行算法时,它会在其已连接的策略对象上调用执行方法。上下文不清楚其所涉及的策略类型与算法的执行方式。
- 客户端(Client)会创建一个特定策略对象并将其传递给上下文。上下文则会提供一个设置器以便客户端在运行时替换相关联的策略。
实例
Strategy.h:
#ifndef STRATEGY_H_
#define STRATEGY_H_
#include <vector>
// 抽象策略类: 排序
class Sort {
public:
virtual void sortVector(std::vector<int> &arr) = 0;
};
#endif // STRATEGY_H_
ConcreteStrategy.h:
#ifndef CONCRETE_STRATEGY_H_
#define CONCRETE_STRATEGY_H_
#include <vector>
#include <string>
#include <utility>
#include <iostream>
#include "Strategy.h"
// 打印vector内容
void printVector(const std::string prefix, const std::vector<int> &vi) {
std::cout << prefix;
for (auto i : vi) {
std::cout << " " << i;
}
std::cout << std::endl;
}
// 具体策略类: 冒泡排序
class BubbleSort : public Sort {
public:
void sortVector(std::vector<int> &vi) override {
printVector("冒泡排序前:", vi);
int len = vi.size();
// 轮次: 从1到n-1轮
for (int i = 0; i < len - 1; ++i) {
// 优化: 判断本轮是否有交换元素, 如果没交换则可直接退出
bool is_exchange = false;
for (int j = 0; j < len - i - 1; ++j) {
if (vi[j] > vi[j+1]) {
std::swap(vi[j], vi[j+1]);
is_exchange = true;
}
}
// 如果本轮无交换, 则可以直接退出
if (!is_exchange) {
printVector("冒泡排序后:", vi);
return;
}
}
printVector("冒泡排序后:", vi);
}
};
// 具体策略类: 选择排序
class SelectionSort : public Sort {
public:
void sortVector(std::vector<int> &vi) override {
printVector("选择排序前:", vi);
// 需要进行 n-1 轮
for (int i = 0; i < vi.size() - 1; ++i) {
// 找到此轮的最小值下标
int min_index = i;
for (int j = i + 1; j < vi.size(); ++j) {
if (vi[j] < vi[min_index]) {
min_index = j;
}
}
std::swap(vi[i], vi[min_index]);
}
printVector("选择排序后:", vi);
}
};
// 具体策略类: 插入排序
class InsertionSort : public Sort {
public:
void sortVector(std::vector<int> &vi) override {
printVector("插入排序前:", vi);
// 第一轮不需要操作, 第二轮比较一次, 第n轮比较 n-1 次
for (int i = 1; i < vi.size(); ++i) {
// 存储待插入的值和下标
int insert_value = vi[i];
int j = i - 1;
while (j >= 0 && vi[j] > insert_value) {
vi[j + 1] = vi[j]; // 如果左侧的已排序元素比目标值大, 那么右移
j--;
}
// 注意这里insert_index 需要+1
vi[j + 1] = insert_value;
}
printVector("插入排序后:", vi);
}
};
#endif // CONCRETE_STRATEGY_H_
Context.h
#ifndef CONTEXT_H_
#define CONTEXT_H_
#include <vector>
#include "Strategy.h"
class ArrayHandler {
public:
void sortVector(std::vector<int> &arr) {
return sort_->sortVector(arr);
}
void setSortStrategy(Sort* sort) {
sort_ = sort;
}
private:
Sort *sort_;
};
#endif // CONTEXT_H_
main.cpp
#include <vector>
#include <algorithm>
#include <random>
#include <iostream>
#include "ConcreteStrategy.h"
#include "Context.h"
std::vector<int> test_array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25};
int main() {
system("chcp 65001");
ArrayHandler array_handler;
{
// 冒泡排序
BubbleSort* bubble_sort = new BubbleSort();
auto rng = std::default_random_engine {};
std::shuffle(std::begin(test_array), std::end(test_array), rng);
array_handler.setSortStrategy(bubble_sort);
array_handler.sortVector(test_array);
delete bubble_sort;
}
{
// 选择排序
SelectionSort* select_sort = new SelectionSort();
auto rng = std::default_random_engine {};
std::shuffle(std::begin(test_array), std::end(test_array), rng);
array_handler.setSortStrategy(select_sort);
array_handler.sortVector(test_array);
delete select_sort;
}
{
// 插入排序
InsertionSort* insert_sort = new InsertionSort();
auto rng = std::default_random_engine {};
std::shuffle(std::begin(test_array), std::end(test_array), rng);
array_handler.setSortStrategy(insert_sort);
array_handler.sortVector(test_array);
delete insert_sort;
}
system("pause");
return 0;
}