设计模式(13) - Strategy策略模式

来源:互联网 发布:淘宝怎么打印发货清单 编辑:程序博客网 时间:2024/06/05 06:09

  1. 意图

  策略模式定义了一系列的算法,并将每个算法封装成一个对象,使得对象之间可以相互替换。这种模式使得算法与使用它的客户分离开来,算法可以独立地进行变化。

  2. UML类图

strategy_diagram
  这里的关键就是将算法的逻辑抽象接口(ContextInterface)封装到一个类中(Context), 再通过委托的方式将具体的算法实现委托给具体的Strategy类来实现(ConcreteStrategyA,B,C类)。

  3. 代码实现

#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模式的代码很直观,关键是将算法的逻辑封装到一个类中。

  4. Example A

#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;}};//Contextclass 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())。

  5. Example B

  在这个例子中,有两种方法来记录联系人信息: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

0 0
原创粉丝点击