前言
刚刚加班回来;哎,公司规定平时加班只有10块钱的餐补;星期六和星期天加班,只给串休假;在国家规定的节假日按照3倍工资发放。那么对于这么多的计算加班费的方法,公司的oa系统是如何进行做的呢?这就要说到今天我这里总结的策略设计模式了。
策略模式
在gof的《设计模式:可复用面向对象软件的基础》一书中对策略模式是这样说的:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。该模式使得算法可独立于使用它的客户而变化。
策略模式为了适应不同的需求,只把变化点封装了,这个变化点就是实现不同需求的算法,但是,用户需要知道各种算法的具体情况。就像上面的加班工资,不同的加班情况,有不同的算法。我们不能在程序中将计算工资的算法进行硬编码,而是能自由的变化的。这就是策略模式。
uml类图
strategy:定义所有支持的算法的公共接口。context使用这个接口来调用某concretestrategy定义的算法;
concretestrategy:实现strategy接口的具体算法;
context:使用一个concretestrategy对象来配置;维护一个对stategy对象的引用,同时,可以定义一个接口来让stategy访问它的数据。
使用场合
当存在以下情况时使用strategy模式:
- 许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法;
- 需要使用一个算法的不同变体;
- 算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构;
- 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的strategy类中以替代这些条件语句。(是不是和状态模式有点一样哦?)
代码实现
首先实现最单纯的策略模式,代码如下:
#include
using namespace std;
// the abstract strategy
class strategy
{
public:
virtual void algorithminterface() = 0;
};
class concretestrategya : public strategy
{
public:
void algorithminterface()
{
cout<<"i am from concretestrategya."<algorithminterface();
}
private:
strategy *pstrategy;
};
int main()
{
// create the strategy
strategy *pstrategya = new concretestrategya;
strategy *pstrategyb = new concretestrategyb;
strategy *pstrategyc = new concretestrategyc;
context *pcontexta = new context(pstrategya);
context *pcontextb = new context(pstrategyb);
context *pcontextc = new context(pstrategyc);
pcontexta->contextinterface();
pcontextb->contextinterface();
pcontextc->contextinterface();
if (pstrategya) delete pstrategya;
if (pstrategyb) delete pstrategyb;
if (pstrategyc) delete pstrategyc;
if (pcontexta) delete pcontexta;
if (pcontextb) delete pcontextb;
if (pcontextc) delete pcontextc;
}
在实际操作的过程中,我们会发现,在main函数中,也就是在客户端使用策略模式时,会创建非常多的strategy,而这样就莫名的增加了客户端的压力,让客户端的复杂度陡然增加了。那么,我们就可以借鉴简单工厂模式,使策略模式和简单工厂模式相结合,从而减轻客户端的压力,代码实现如下:
#include
using namespace std;
// define the strategy type
typedef enum strategytype
{
strategya,
strategyb,
strategyc
}strategytype;
// the abstract strategy
class strategy
{
public:
virtual void algorithminterface() = 0;
virtual ~strategy() = 0;
};
strategy::~strategy()
{}
class concretestrategya : public strategy
{
public:
void algorithminterface()
{
cout << "i am from concretestrategya." << endl;
}
~concretestrategya(){}
};
class concretestrategyb : public strategy
{
public:
void algorithminterface()
{
cout << "i am from concretestrategyb." << endl;
}
~concretestrategyb(){}
};
class concretestrategyc : public strategy
{
public:
void algorithminterface()
{
cout << "i am from concretestrategyc." << endl;
}
~concretestrategyc(){}
};
class context
{
public:
context(strategytype strategytype)
{
switch (strategytype)
{
case strategya:
pstrategy = new concretestrategya;
break;
case strategyb:
pstrategy = new concretestrategyb;
break;
case strategyc:
pstrategy = new concretestrategyc;
break;
default:
break;
}
}
~context()
{
if (pstrategy) delete pstrategy;
}
void contextinterface()
{
if (pstrategy)
pstrategy->algorithminterface();
}
private:
strategy *pstrategy;
};
int main()
{
context *pcontext = new context(strategya);
pcontext->contextinterface();
if (pcontext) delete pcontext;
}
在上面这个代码中,其实,我们可能看到的更多的是简单工厂模式的应用,我们将策略模式将简单工厂模式结合在了一起,让客户端使用起来更轻松。
总结
策略模式和状态模式,是大同小异的;状态模式讲究的是状态的变化,和不同状态下,执行的不同行为;而策略模式侧重于同一个动作,实现该行为的算法的不同,不同的策略封装了不同的算法。策略模式适用于实现某一功能,而实现该功能的算法是经常改变的情况。在实际工作中,遇到了实际的场景,可能会有更深的体会。比如,我们做某一个系统,该系统可以适用于各种数据库,我们都知道,连接某一种数据库的方式是不一样的,也可以说,连接数据库的“算法”都是不一样的。这样,我们就可以使用策略模式来实现不同的连接数据库的策略,从而实现数据库的动态变换。