策略模式(Strategy Pattern)
定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户
设计原则1:找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起
设计原则2:针对接口(超类)编程,而不是针对实现编程
设计原则3:多用组合,少用继承
问题:一个模拟鸭子游戏SimUDuck,游戏中会出现各种鸭子,一边游泳戏水,一边呱呱叫。现在想添加飞行和显示名字的方法。但是鸭子有很多种,比如说玩具鸭子不能飞,它吱吱叫,甚至还存在模型鸭子,它的飞行行为具有火箭动力。原始的设计可能是这样的:
当有一些鸭子都是”吱吱叫"的时候,在具体的继承类里面要重写很多次这个方法,fly 和 quack 方法没有很好的得到复用。
分析:要把类中变化的部分取出来,并且”封装“起来,好让其他部分不受影响。上面的问题中,除了fly()和quack()的问题之外,Duck类还是能正常工作的。但是fly()和quack()会随着鸭子的不同而改变,为了要把这两个行为从Duck 类中分开,我们将把它们从Duck类中取出来,建立一组新类来代表每个行为。
实现鸭子的行为的时候,我们是有两个接口(考虑到原则2)FlyBehavior 和QuackBehavior,还有它们对应的类,负责实现具体的行为。
class FlyBehavior{
public:
virtual void fly() =0;
};
class FlyWithWings: virtual public FlyBehavior{
public:
void fly(){
cout << "I' m fly with wings" << endl;
}
};
class FlyNoWay:virtual public FlyBehavior{
public:
void fly(){
cout << "I can't fly" << endl;
}
};
class QuackBehavior{
public:
virtual void quack() = 0;
};
class Quack:virtual public QuackBehavior{
public:
void quack(){
cout <<"Quack"<<endl;
}
};
class MuteQuack:virtual public QuackBehavior{
public:
void quack(){
cout << "<<Silence>>" << endl;
}
};
class Squeak: virtual public QuackBehavior{
public:
void quack(){
cout << "Squeak" << endl;
}
};
这样的设计,可以让飞行和咕咕叫的动作被其他的对象复用,因为这些行为已经与鸭子类无关了。为我们可以新增一些行为,不会影响到既有的行为类,也不会影响使用到飞行行为的鸭子类。这样一来,既有了复用的好处,也没有继承带来的包袱。
另外一个值得注意的地方就是,要把飞行行为和咕咕叫动作委托给别人做,甚至可以在程序里面动态的改变这些行为。
class Duck{
public:
QuackBehavior* quackBehavior;
FlyBehavior* flyBehavior;
Duck(){
}
void swim(){
cout << "I am swimming " << endl;
}
virtual void display(){
cout <<"Duck" << endl;
}
void performFly(){
flyBehavior->fly();
}
void setFlyBehavior(FlyBehavior* fb){
flyBehavior =fb;
}
void performQuack(){
quackBehavior->quack();
}
void setQuackBehavior(QuackBehavior* qb){
quackBehavior = qb;
}
virtual ~Duck(){
}
};
class MallardDuck: public Duck{
public:
MallardDuck(){
flyBehavior = new FlyWithWings();
quackBehavior = new Quack();
}
void display(){
cout << " I am a Mallard Duck" << endl;
}
~MallardDuck(){
delete quackBehavior;
delete flyBehavior;
}
};
运行结果如下:
int main(){
Duck* mallard = new MallardDuck();
mallard->display();
mallard->performFly();
}
现在我们要把鸭子的飞行动作改成火箭动力的只需要很少的代码来完成
class FlyRocketPowered: virtual public FlyBehavior{
public:
void fly(){
cout << "I 'm flying with a rocket" << endl;
}
};
int main(){
Duck* mallard = new MallardDuck();
mallard->display();
mallard->performFly();
mallard->setFlyBehavior(new FlyRocketPowered());
mallard->performFly();
}
运行结果: