Head First 设计模式 C++实现-Strategy(策略模式)
转贴地址:http://blog.csdn.net/NE_Team/archive/2008/07/21/2685689.aspx
模式定义:定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
个人见解:基本上所有的模式都是在体现oo的一个设计原则,弱关联(其中之一)。
书上介绍了一个例子,是关于鸭子的,总体的问题是过多的运用了继承,使整个设计过于紧密,类之间是存在强关联,在软件后期开发弊端凸显。不过这个例子可能和模式本身定义关联不是太大,所以自己想了以下这个例子,用以说明策略模式。
案例:一个公司,准备做一套计算器, 需要一套软件设计,按照一般的oo设计者来说,可能会用到以下的设计思路
计算器基类Calculator提供两个方法,Addition()和Subtract(),对于这个设计,初期看不出什么好与不好的,因为它确实能够工作,那么它会在什么时候出现问题呢,
随着业务的深入,这个时候发现,有新的计算器要来了,那么按照这位设计师的想法,开始从基类派生出来一个Calculator_Three,然后实现两个函数,新的计算器出来了。
这个时候的Addition和Subtract重写过的,一个问题出在这里,每产生一个新的计算器,我们就要重写这两个方法,毕竟有些计算器方法还是一样的,有人会说,如果有方法一样的计算器,那么我们就让他们保持is-a关系,让一个继承于另外一个,这样虽然能够解决问题,但是这样让人感觉好像就是让猫继承于狗一样别扭。另外一个问题,如果计算器1号突然心血来潮,说自己要用计算器2的Addition方法了,该怎么办?去把2的代码拷贝过来?
另外这样的设计更多的问题会凸显在算法方面,突然有一天,他们突然开始做一些小型的电脑了,电脑只是比他们先进一点,但是如果要说加减这些算法,大多数都是一样的,这个时候难道把他们的代码一段一段的拷贝过去,去适应新的程序?
看看上面的一系列问题,想想整个事情错在什么地方,答案:对于程序变化的部分欠考虑。
对于过早的将算法或者实现绑定到类的设计过后,使得整个程序出现了一种强关联的形式,导致后面的开发陷入一个泥潭,无法或者很难继续,并且对于这钟需要重复利用的算法来说,这样的设计无疑就是要让后期开发在不断的拷贝代码之间进行,并且你要保证你没拷贝错,那应该怎么解决问题呢。
这个时候就应该策略模式登场了,好好分析以下策略模式的定义,我们会好好想下这个计算器,它应该是这样:动态决定算法类型,算法与实际对象相分离,算法可以用作它用,计算器可以方便的具备其它功能或者说是算法。
开始OO设计之旅:
首先重新定义这个计算器基类如下:
这里定义了两个行为类,一个是加法,一个是减法,而计算器基类仍然有以前的两个接口,不过现在多了一些东西,他包含了两个行为类的指针,基类的Addition实现和以前不同的是,现在这个实现是通过m_pAddtionBehavior这个指针来调用加法行为类中的Addition,这是一种组合的方法,C++代码如下
//加法类
class AdditionBehavior
{
public:
virtual void Addition();
};
//减法类
class SubtractBehavior
{
public:
virtual void Subtract();
};
//计算器类
class Calculator
{
public:
Calculator();
virtual ~Calculator();
public:
virtual void Addition()
{
m_pAdditionBehavior->Addition();
}
virtual void Subtract();
{
m_pSubtractBehavior->Subtract();
}
virtual void SetAdditionBehavior(AdditionBehavior* pBehavior)
{
m_pAdditionBehavior = pBehavior;
}
virtual void SetSubtractBehavior(SubtractBehavior* pBehavior)
{
m_pSubtractBehavior = pBehavior;
}
private:
AdditionBehavior* m_pAdditionBehavior;
SubtractBehavior* m_pSubtractBehavior;
};
//加法派生类
class AddtionBehavior_One : public AdditionBehavior
{
public:
virtual void Addition();
};
///////////////////////////////////////////////////////////////////////////////////////////////////
SetAdditionBehavior是为了让计算器可以在运行时动态的替换算法,上面的代码可以在计算器的构造函数参数里面加个限定,必须要两个行为类的指针作为参数,不过这样好像又是一个强关联了,这个就看自己程序了,如果不加参数,在调用两个指针的方法时候需要检查指针有效性,
下面讲到了算法复用
class Computer
{
public:
virtual void Addition()
{
m_pAdditionBehavior->Addition();
}
virtual void Subtract();
{
m_pSubtractBehavior->Subtract();
}
virtual void SetAdditionBehavior(AdditionBehavior* pBehavior)
{
m_pAdditionBehavior = pBehavior;
}
virtual void SetSubtractBehavior(SubtractBehavior* pBehavior)
{
m_pSubtractBehavior = pBehavior;
}
private:
AdditionBehavior* m_pAdditionBehavior;
SubtractBehavior* m_pSubtractBehavior;
};
一个新的类型,简单电脑,同样也可以用这些加减法了。只要你希望,你可以让这个电脑或者计算器之间的任何方法重用。
上面代码的测试如下
cout << "I'm calculator" << endl;
//计算器
Calculator* pCalculator = new Calculator;
pCalculator->SetAdditionBehavior(new AdditionBehavior);
pCalculator->Addition();
pCalculator->SetAdditionBehavior(new AddtionBehavior_One);
pCalculator->Addition();
cout << endl;
cout << "I'm computer" << endl;
//简单电脑
Computer* pComputer = new Computer;
pComputer->SetAdditionBehavior(new AdditionBehavior);
pComputer->Addition();
结果:
I'm calculator
AdditionBehavior
AddtionBehavior_One
I'm computer
AdditionBehavior
书上写了一句很好的话 多用组合,少用继承 针对接口编程