开始之前
每次看书都会收获不一样的感受,走过的弯路越多回头来看前人整理的书籍,才发现原来都在上面。
框架写的越多,看起HeadFirst越能体会它的好。
策略模式定义
定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计原则
1、找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
2、针对接口编程,而不是针对实现编程。
3、多用组合,少用继承。
这是书上的Tips,前人总结的准则,在设计系统应该多加参考。
案例
在一个模拟鸭子游戏:SimUDuck。游戏中有各种鸭子,一边游泳戏水,一边呱呱叫。现在设计了一个Duck的类,并让各种鸭子继承此超类。
问题:现在新增了一个需求,需要让MallardDuck和RedheadDuck有飞的方法,同时新增一个DecoyDuck(诱捕鸟)子类不要飞的方法。
一般的做法:
在Duck类里写一个Fly()方法,让子类继承。MuteDuck中覆盖去掉实现。但是,这是针对实现编程,且每多一个子类,便要多设置一次。
策略模式实现的做法:
在将fly方法提出来,单独写一个接口类如下:
// 关于飞的接口类 class IFlyBehavior { virtual void fly() =0 ; } // 可以飞的实现 class FlyWithWings:public IFlyBehavior { virtual void fly() override{ printf("fly with wings!");}; } // 不能飞的实现 class NoWingsFly:public IFlyBehavior { virtual void fly() override{ printf("no fly!"); }; }
这里方便显示直接将实现也写在头文件定义里,一般复杂的实现要单独在cpp中实现,这样才不会导致编译生成过大。
在有了飞的方法类之后,我们只需要让Duck基类拥有IFlyBehavior对象,然后在新增的doFly()方法中调用即可。
class Duck { public: void quack(); void swim(); void display(); void doFly(); protected: IFlyBehavior* m_pFlyBehavior; }
void Duck::doFly() { if(m_pFlyBehavior) { m_pFlyBehavior->fly(); } }
然后再子类的构造函数中分别继承的IFlyBehavior对象进行不同的赋值。
// 能飞的绿头鸭 MallarDuck::MallarDuck(void) { m_pFlyBehavior = new FlyWithWings(); } // 不能飞的橡胶鸭子 DecoyDuck::DecoyDuck(void) { m_pFlyBehavior = new NoWingsFly(); }
这样的设计,可以让飞行这一行为被其他非鸭子类对象复用。同时可以再新增新的行为,也不影响鸭子类的飞行行为。
结尾
“有一个(拥有)” 可能比 “是一个” 更好。 这就是组合的好处了。