目录
1.意图
策略模式定义了一系列的算法,并将每个算法封装成一个对象,使得对象之间可以相互替换。这种模式使得算法与使用它的客户分离开来,算法可以独立地进行变化。
2.UML类图
3.GOF角色说明
Strategy(策略):定义所有支持的算法的公共接口。Context使用这个接口来调用某ConcreteStrategy定义的算法。
ConcreteStrategy(具体策略):以Strategy接口实现某具体算法。
Context(上下文):用一个ConcreteStrategy对象来配置;维护一个对Strategy对象的引用;可定义一个接口来让Strategy访问它的数据。
这里的关键就是将算法的逻辑抽象接口(ContextInterface)封装到一个类中(Context), 再通过委托的方式将具体的算法实现委托给具体的Strategy类来实现(ConcreteStrategyA,B,C类)。
4.代码实现
#include<iostream>
using namespace std;
class Strategy
{
public:
Strategy(){}
virtual ~Strategy() {}
virtual void AlgorithmInterface() = 0;
};
class ConcreteStrategyA:public Strategy
{
public:
ConcreteStrategyA() {}
virtual ~ConcreteStrategyA()
{
cout<<"ConcreteStrategyA::Destructor"<<endl;
}
void AlgorithmInterface()
{
cout<<"ConcreteStrategyA::AlgorithmInterface"<<endl;
}
};
class ConcreteStrategyB:public Strategy
{
public:
ConcreteStrategyB() {}
virtual ~ConcreteStrategyB()
{
cout<<"ConcreteStrategyB::Destructor"<<endl;
}
void AlgorithmInterface()
{
cout<<"ConcreteStrategyB::AlgorithmInterface"<<endl;
}
};
/*
*Context类是Strategy模式的关键,也是Strategy模式与Template模式的根本区别。
*Strategy通过“组合”(委托)方式实现算法(实现)的异构,而Template模式则采取的是继承的方式。
*这两个模式的区别也是继承和组合两种实现接口重用的方式的区别。
*/
class Context
{
public:
Context(Strategy *stg)
{
_stg = stg;
}
~Context()
{
if(NULL!=_stg)
delete _stg;
}
void ContextInterface()
{
_stg->AlgorithmInterface();
}
private:
Strategy* _stg;
};
int main()
{
Strategy *pStg = new ConcreteStrategyA;
Context *pCtx = new Context(pStg);
pCtx->ContextInterface();
if(NULL!=pCtx)
delete pCtx;
pStg = new ConcreteStrategyB;
pCtx = new Context(pStg);
pCtx->ContextInterface();
if(NULL!=pCtx)
delete pCtx;
system("pause");
return 0;
}
运行结果为:
ConcreteStrategyA::AlgorithmInterface
ConcreteStrategyA::Destructor
ConcreteStrategyB::AlgorithmInterface
ConcreteStrategyB::Destructor
Strategy模式的代码很直观,关键是将算法的逻辑封装到一个类中。
5.实际场景一
#include<iostream>
using namespace std;
//排序行为
class SortBehavior
{
public:
virtual void sort() const = 0;
};
//归并排序
class Merge:public SortBehavior
{
public:
virtual void sort() const
{
cout<<"Merge sort()"<<endl;
}
};
//快速排序
class Quick:public SortBehavior
{
public:
virtual void sort() const
{
cout<<"Quick sort()"<<endl;
}
};
//堆排序
class Heap:public SortBehavior
{
public:
virtual void sort() const
{
cout<<"Heap sort()"<<endl;
}
};
//搜索行为
class SearchBehavior
{
public:
virtual void search() const = 0;
};
//连续搜索
class Sequential:public SearchBehavior
{
public:
virtual void search() const
{
cout<<"Sequential search()"<<endl;
}
};
//二叉树搜索
class BinaryTree:public SearchBehavior
{
public:
virtual void search() const
{
cout<<"BinaryTree search()"<<endl;
}
};
//哈希表搜索
class HashTable:public SearchBehavior
{
public:
virtual void search() const
{
cout<<"HashTable search()"<<endl;
}
};
//Context
class Context
{
private:
SortBehavior *_sort;
SearchBehavior *_search;
public:
Context(){}
void set_sort(SortBehavior *s)
{
_sort = s;
}
void set_search(SearchBehavior *s)
{
_search = s;
}
void sort() const
{
_sort->sort();
}
void search() const
{
_search->search();
}
};
int main(int argc, char *argv[])
{
Merge merge;
Quick quick;
Heap heap;
Sequential sqn;
BinaryTree bt;
HashTable ht;
Context ctx;
ctx.set_sort(&merge);
ctx.sort();
ctx.set_search(&bt);
ctx.search();
system("pause");
return 0;
}
运行结果为:
Merge sort()
BinaryTree search()
基于以上结果,可以得到下面的总结:
1).存在两个接口: SortBehavior以及SearchBehavior,连同实现了每个具体行为的相关的类。
2).依靠这种设计,其他类型的对象可以重用这里的搜索以及排序行为,因为这些行为不再被隐藏于我们的聚合类中。
3).并且,无需修改已存在行为类的任何数据,就可以添加新的行为进来。
4).定义了下面的对象指针,它们在运行时期间指向特定的行为类。
class Context {
private:
SortBehavior *_sort;
SearchBehavior *_search;
}
5).依靠这些对象指针,我们可以实现每种行为
void sort() const
{
_sort->sort();
}
void search() const
{
_search->search();
}
6).Context对象不会自己去处理排序行为,而是将此行为委托给对象指针_sort去处理。
7).我们无需关心Context对象类型是什么,只需关心它是否知道如何去排序(如何调用sort()函数)。
8).实际上,上面代码中我们也使用了组合来提供更多的灵活性。它不仅使得我们可以把算法系列封装在它们自己各自的类中,还可以让我们在运行时期间改变行为,只要组合的这个对象实现了正确的行为接口(例如,_sort实现了sort(), _search实现了search())。
6.实际场景二
在这个例子中,有两种方法来记录联系人信息:stream & database. 对应的两个类(StreamRecord以及DatabaseRecord),通过基类函数store(),共享了相同的接口。
class Record
{
public:
virtual void start_record() = 0;
virtual void store_field(const string &name, const string &value) = 0;
virtual void finish_record() = 0;
virtual ~Record() {}
};
struct ContactData
{
string first_name, last_name, phone, email;
};
class ContactRecorder
{
public:
ContactRecorder(Record *a) : _record(a)
{
assert(NULL!=a);
}
void store(const ContactData &data)
{
assert(NULL!=_record);
_record->start_record();
_record->store_field("first name", data.first_name);
_record->store_field("last name", data.last_name);
_record->store_field("phone", data.phone);
_record->store_field("email", data.email);
_record->finish_record();
}
private:
Record *_record;
};
class StreamRecorder:public Record
{
public:
StreamRecorder(ostream &s, const string &record_name=string()):_ostream(s), \
_record_name(record_name)
{
}
void start_record()
{
_ostream<<_record_name<<"(";
}
void store_field(const string &name, const string &value)
{
_ostream<<name<<": "<<value<<"; ";
}
void finish_record()
{
_ostream<<") "<<endl;
}
void set_record_name(const string &name)
{
_record_name = name;
}
private:
ostream &_ostream;
string _record_name;
};
class MySql {};
class DatabaseRecorder:public Record
{
public:
DatabaseRecorder():_dbConnection(new MySql) {}
void start_record()
{
cout<<"start tranaction"<<endl;
}
void store_field(const string&name, const string &value)
{
cout<<"insert into table"<<endl;
}
void finish_record()
{
cout<<"finish transaction"<<endl;
}
private:
MySql *_dbConnection;
};
int main()
{
ContactData data = {"Phill", "Collyns", "123-456-789", "pc@email.com"};
StreamRecorder smrd(std::cout);
ContactRecorder contact(&smrd);
contact.store(data);
DatabaseRecorder dbRecord;
ContactRecorder contact2(&dbRecord);
contact2.store(data);
system("pause");
return 0;
}
运行结果为:
(first name: Phill; last name: Collyns; phone: 123-456-789; email: pc@email.com; )
start tranaction
insert into table
insert into table
insert into table
insert into table
finish transaction