策略模式
策略模式:定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计原则1:找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起。
设计原则2:针对接口编程,而不是针对实现编程。
设计原则3:多用组合,少用继承。
第一种设计:每次加入一种新类型的鸭子,都要判断该类鸭子怎么飞,怎么叫。如果与基类不一致还需要覆盖,而且可能子类中有许多鸭子都采用一样的方法(不能飞)来覆盖,产生重复代码。
第二种设计:为了防止每次覆盖会产生重复代码,可以加入两个类,一个是Flyable,一个是Quackable,每次加入一个新的鸭子,判断能否飞和叫,然后根据判断结果进行继承,这样解决了第一种设计中的覆盖时产生重复代码的问题,但是,需要为现有的每个类进行改写(至少要改动继承的内容),然而如果将两个类Flyable和Quackable设为抽象类,则需要在每个能飞能叫的鸭子子类中实现fly和quack,这也会导致大量重复的代码,如果两个类不为抽象类,使一个较好的设计(至少不会产生重复代码),但是不要忘了,当鸭子的飞行和叫的行为变得更加多态化的情况,这种设计将再次不适用。
到此为止我已经发现问题所在了:当子类中对于一个动作有若干种行为,但是每一种行为都有多个子类与之对应,这是如果将父类中该动作设为纯虚函数,简单采用多态,会产生大量重复的代码,如果父类中该动作设为虚函数,我还不知道要把那一种行为设在父类当中,这样还是会产生大量重复的代码。
再进一步提炼该问题的本质:其实是鸭子数和行为数不一样,如果一个鸭子一个行为,或者所有鸭子一个行为都好办。如果鸭子数大于行为数,那肯定会存在这个问题。但是,如果我们设计一个飞行抽象类,那么各种飞行行为子类的数目一定等于行为数,这个问题就迎刃而解了。
采用策略模式所有的代码重复问题均已经解决。而且他的好处远不止如此,还有以下两点(这才是精髓所在),其实正确引入策略模式的方法是,每次要改变某种鸭子的飞行行为的时候,都需要改变这种鸭子的代码,原因是,继承让行为死死地绑定在类中。采用策略模式(组合策略)可以把飞行行为和鸭子分离开来,改变某种鸭子的飞行行为,只需要改变其组合的策略。
1) 第二种设计存在的问题还有,灵活性不够,相当于每种鸭子的飞行和呱呱叫的行为是固定的也就是针对实现编程而非针对接口编程,当需要改变行为的时候需要重新修改代码,而策略模式实现运行时确定鸭子的飞行和呱呱叫的行为。这样当想改变鸭子的行为的时候,不需要修改代码,只需要增加行为子类。然后动态绑定到鸭子。把变化的部分抽出来当作基类其实并不能封装变化,抽出变化后,要采用组合才能真正地实现封装变化。
2) 采用策略模式还可以复用飞行算法,不一定非要这个鸭子体系可以使用,比如鸭鸣器也可以使用呱呱叫。
#ifndef DUCK_H #define DUCK_H #include "FlyBehavior.h" #include "QuackBehavior.h" class Duck { public: void swim(); virtual void display() = 0 ; void performFly() { flyBehavior->fly(); } void performQuack() { quackBehavior->quack(); } void setFlyBehavior(FlyBehavior* fly) { flyBehavior = fly; } void setQuackBehavior(QuackBehavior* quack) { quackBehavior = quack; } public: FlyBehavior* flyBehavior; QuackBehavior* quackBehavior; }; #endifDuck.h
#ifndef MALLARDDUCK_H #define MALLARDDUCK_H #include "Duck.h" #include "FlyBehavior.h" #include "FlyWithWings.h" #include "Quack.h" #include "QuackBehavior.h" #include <iostream> class MallardDuck : public Duck { public: MallardDuck() { flyBehavior = new FlyWithWings; quackBehavior = new Quack; } virtual void display() { std::cout<<"I'm mallard duck!"<<std::endl; } }; #endif
#ifndef REDHEADDUCK_H #define REDHEADDUCK_H #include "Duck.h" #include "Squeak.h" #include "FlyWithWings.h" #include <iostream> class RedheadDuck : public Duck { public: RedheadDuck() { quackBehavior = new Squeak; flyBehavior = new FlyWithWings; } virtual display() { std::cout<<"I'm red head duck!"<<std::endl; } } #endif
#ifndef QUACKBEHAVIOR_H #define QUACKBEHAVIOR_H class QuackBehavior { public: virtual void quack() = 0; }; #endif
#ifndef QUACK_H #define QUACK_H #include "QuackBehavior.h" #include <iostream> class Quack : public QuackBehavior { public: void quack() { std::cout<<"guagua jiao!"<<std::endl; } }; #endif
#ifndef SQUEAK_H #define SQUEAK_H #include "QuackBehavior.h" #include <iostream> class Squeak : public QuackBehavior { public: void quack() { std::cout<<"zhizhi jiao!"<<std::endl; } }; #endif
#ifndef MUTEQUACK_H #define MUTEQUACK_H #include "QuackBehavior.h" #include <iostream> class MuteQuack : public QuackBehavior { public: void quack() { std::cout<<"buhui jiao!"<<std::endl; } }; #endif
#ifndef FLYBEHAVIOR_H #define FLYBEHAVIOR_H class FlyBehavior { public: virtual void fly() = 0; }; #endif
#ifndef FLYNOWAY_H #define FLYNOWAY_H #include "FlyBehavior.h" #include <iostream> class FlyNoWay : public FlyBehavior { public: void fly() { std::cout<<"Fly no way!"<<std::endl; } }; #endif
#ifndef FLYWITHWINGS_H #define FLYWITHWINGS_H #include "FlyBehavior.h" #include <iostream> class FlyWithWings : public FlyBehavior { public: void fly() { std::cout<<"Fly with wings!"<<std::endl; } }; #endif
#include "MallardDuck.h" #include "Duck.h" #include "FlyNoWay.h" int main() { Duck* md = new MallardDuck(); md->performFly(); md->setFlyBehavior(new FlyNoWay); md->performFly(); return 1; }

浙公网安备 33010602011771号