博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式(13) - Strategy策略模式
阅读量:4072 次
发布时间:2019-05-25

本文共 3732 字,大约阅读时间需要 12 分钟。

目录


1.意图

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

2.UML类图

strategy_diagram

3.GOF角色说明

  Strategy(策略):定义所有支持的算法的公共接口。Context使用这个接口来调用某ConcreteStrategy定义的算法。

  ConcreteStrategy(具体策略):以Strategy接口实现某具体算法。

  Context(上下文):用一个ConcreteStrategy对象来配置;维护一个对Strategy对象的引用;可定义一个接口来让Strategy访问它的数据。

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

4.代码实现

#include
using namespace std;class Strategy{public: Strategy(){} virtual ~Strategy() {} virtual void AlgorithmInterface() = 0;};class ConcreteStrategyA:public Strategy{public: ConcreteStrategyA() {} virtual ~ConcreteStrategyA() { cout<<"ConcreteStrategyA::Destructor"<
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
using namespace std;//排序行为class SortBehavior{public: virtual void sort() const = 0;};//归并排序class Merge:public SortBehavior{public: virtual void sort() const { cout<<"Merge 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<
<<": "<
<<"; "; } void finish_record() { _ostream<<") "<

运行结果为:

(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

转载地址:http://aleji.baihongyu.com/

你可能感兴趣的文章
linux中时间精度的获取问题
查看>>
cancel_rearming_delayed_workqueue 函数使用的一个小备注
查看>>
使用LOGFONT修改windows sdk下字体为系统字体
查看>>
wind32 sdk下修改控件的字体
查看>>
c列举文件目录
查看>>
解决MFC下线程创建的一个编译错误
查看>>
在HW这四个月
查看>>
最近的生活
查看>>
freemarker下的一个错误的解决
查看>>
MFC的一些记录
查看>>
MFC的一些记录
查看>>
MFC中给应用程序添加托盘支持
查看>>
MFC上显示GIF图片(使用 GIF Animation Control控件)
查看>>
MFC中时间显示
查看>>
MFC DLL的一些知识
查看>>
easyUI的布局入门
查看>>
vsftp下的一个小错误
查看>>
jdbc查询超大数据集内存溢出
查看>>
acegi的一个异常错误
查看>>
java实现的KMP算法
查看>>