设计模式 策略模式
Posted 飞鸢逐浪
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式 策略模式相关的知识,希望对你有一定的参考价值。
摘自<<Head First Design Pattterns>> chapter 1
1 飞翔的鸭子
假设开发一款模拟鸭子的游戏。首先设计一个鸭子母类,里面有鸭子的叫声、游泳和外形三个成员函数,然后在野鸭和红头鸭两个子类中重写继承的外形函数。
现在更进一步,要求鸭子会飞,应该如何设计程序呢?
2 两种方法
1) 继承
为 Duck 母类添加 fly() 成员函数,然后各个子类继承 fly()
问题: 并不是所有的鸭子都会飞,比如“煮熟的鸭子”。
解决: 不会飞的鸭子自母类继承 fly() 后,重写该函数。
因为鸭子会不会飞的问题,又发现一个bug,并不是所有的鸭子都会叫,比如“大黄鸭”。因此,不同的子类也需要重写 quack()
此时问题又来了,公司开发的是游戏软件,要求游戏每三个月更新一次,每次更新后鸭子的飞行方式和叫声都可能发生新的变化。那么,岂不是每三个月都要重写 RubberDuck 和 DecoyDuck 子类甚至更多子类的 fly() 和 quack() 函数,有点繁琐。
于是,有了第二个方法...
2) 接口 (interface)
视会飞和会叫为一种能力,并将 Flyable 和 Quackable 做成接口 (interface),然后在里面加上相应的函数 fly() 和 quack()
这样,只有会飞的子类实现该接口 Flyable, 并且具有 fly() 函数。同理只有会叫的子类实现接口 Quackable 且有 quack() 函数。
问题又来了,飞行是鸭子的一种行为,不同的鸭子,其各自飞行的方式也不相同。
很显然,每个子类中还得重写 fly() 和 quack()。因此,单纯的使用接口或继承都不是最佳的方法。
那么,到底什么方法能完美解决鸭子 fly 和 quack 的问题呢?不着急,先看下面的三个设计原则。
3 设计原则
1) identify what varies and separate them from what stays the same
把变化的摘出来,和不变的分割开来
2) program to an interface, not an implementation
3) favor composition over inheritance
HAS-A better than IS-A
4 策略模式
现在引出策略模式
defines a family of algorithms, encapsulates each one, and makes them interchangeable.
(Strategy lets the algorithm vary independently from clients that use it)
1) client
Java: 在 Duck 母类中定义 FlyBehavior 和 QuackBehavior 的成员对象 (FlyBehavior flyBehavior)
C++: 在 Duck 母类中定义 FlyBehavior 和 QuackBehavior 的指针 (FlyBehavior * pflyBehavior)
2) encapsulated fly behavior
把飞行封装为接口,里面具体实现不同的飞行方式,即将各种”飞行方式“视为一系列”算法“,添加或者修改算法都在这个接口里面进行。
这样,不同的鸭子子类,只需通过母类中的成员对象 (flyBehavior) 调用相应的”飞行算法“即可。
3) encapsulated quack behavior
Java: 直接使用关键字 interface 便可将 QuackBehavior 定义成接口
C++: 接口 ≈ 抽象基类,将 QuackBehavior 定义为抽象基类,也即声明 quack() 为纯虚函数, 具体代码形式为 “void quack() = 0”
以上是关于设计模式 策略模式的主要内容,如果未能解决你的问题,请参考以下文章