(1)定义:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
①算法是同一接口的不同实现,地位是平等的,可以相互替换。
②引入上下文对象,可以实现让算法能独立使用它的客户。因为这个对象负责持有算法,但不负责决定具体选用哪个算法,把选择算法的功能交给了客户。
③当客户通知上下文对象执行功能的时候,上下文会转调具体的算法。
(2)策略模式的结构和说明
①Strategy:策略接口,用来约束一系列具体的策略算法。Context使用这个接口来调用具体的策略实现定义的算法。
②ConcreteStrategy:具体的策略实现,也就是具体的算法实现。
③Context:上下文,负责和具体的策略类交互。通常会持有一个真正的策略实现,上下文还可以让具体的策略类来获取上下文的数据,甚至让具体的策略来回调上下文的方法
思考策略模式
(1)策略模式的本质:分离算法,选择实现
(2)策略模式的重心:不是如何实现算法,而是如何组织、调用这一系列的算法,从而让程序结构更加灵活,具有更好的维护性和扩展性。
(3)算法的平等性
策略模式一个很大的特点就是各个策略算法的平等性。对于一系列具体的策略算法大家的地位是完全一样的,所以才能实现算法之间可以相互替换。可以这样描述策略算法:它是相同行为的不同实现。(如同样是打折这一行为,但商家可以在不同的时间,选择不同的打折策略)
(4)谁来选择具体的策略算法
①一个地方是在客户端,当使用上下文的时候,由客户端选择具体的策略算法,然后把这个策略算法设置给上下文。
②还有一个地方是由上下文选择具体的策略算法。而状态模式可以由具体的状态实现去切换不同的状态。
(5)Strategy角色的实现方式:可以使用接口或抽象类,特别是当多个算法具有公共功能的时候,可以把Strategy实现成为抽象类。
(6)运行时策略的唯一性:运行期间,策略模式在每一个时刻只能使用一个具体的策略实现对象,虽然可以动态地在不同策略实现中切换,但是同时只能使用一个。
(7)Context和Strategy的关系
①在策略模式中,通常是上下文使用具体的策略实现对象。反过来,策略实现对象也可以从上下文获取所需要的数据。因此可以将上下文当作参数传递给策略实现对象。
②在这种情况下,上下文封装着具体策略对象进行算法运算所需要的数据,具体策略对象通过回调上下文的方法来获取这些数据。
容错恢复机制(1)在程序运行的时候,正常情况下应该按照某种方式来做,此时如果发生错误的话,系统并不会崩溃,而是有容忍出错的能力。
(2)不但能容忍程序运行出现错误,还提供出现错误后的备用方案,也就是恢复机制来代替正常执行的功能,使程序继续向下运行。如日志记录,一般会记录在数据库里,但是当数据库暂时连不上时,可先记录在文本文件里,然后在合适的时候再转录到数据库中。
【编程实验】日志记录策略
//行为型模式——策略模式
//场景:容错恢复机制(策略模式+模板方法)
/*
将日志记录到数据库和文件
*/
#include <iostream>
#include <string>
using namespace std;
//日志记录策略的接口
class CLogStrategy{
public:
virtual void WriteLog(string log) = 0;//记录日志
virtual ~CLogStrategy(){}
};
//实现日志策略接口
//把日志记录到数据库
class CDbLog : public CLogStrategy{
public:
void WriteLog(string log){
//制造错误,模仿数据库断开连接
try{if(log.length() >= 30) throw -1;}
catch(...){throw -1;}
//数据连接正常时,直接写入数据库
cout << "Write log : \"" << log << "\" into Database." << endl;
}
};
//把日志记录到文件
class CFileLog : public CLogStrategy{
public:
void WriteLog(string log){cout << "Write log : \"" << log << "\" into File." << endl;}
};
//日志记录的上下文
class CLogContext{
private:
CLogStrategy* pStrategy;
public:
CLogContext(){pStrategy = NULL;}
~CLogContext(){Clr();}
void Clr(){
if(pStrategy != NULL){
delete pStrategy; pStrategy = NULL;
}
}
void DoLog(string log){
//在上下文中,自行实现对具体策略的选择
try{//优先选用策略:记录到数据库
Clr();
pStrategy = new CDbLog();
pStrategy->WriteLog(log);
}
catch(...){//出错了,那就记录到文件中
Clr();
pStrategy = new CFileLog();
pStrategy->WriteLog(log);
}
Clr();
}
};
void StrategyTst()
{
CLogContext oLogContext;
oLogContext.DoLog("abcdefghijklmnopqrstuvwxyz");
oLogContext.DoLog("abcdefghijklmnopqrstuvwxyz1234");
}