《设计模式》——策略模式

95 阅读3分钟

本次设计原则

  • 找出应用中可能需要变化之处,把他们独立出来,不要和不需要变化的代码混在一起
  • 针对接口编程,而不是针对实现编程
  • 多用组合,少用继承

用委托定义算法族,让算法的变化独立于使用算法的客户

基本情景:用继承解决问题

一款模拟鸭子游戏,其中有多种鸭子,基本的设计方式:设计一个超类Duck,然后让各种鸭子继承此超类。包含叫(quack)、游泳(swim)、外观(display)等方法,其中display是抽象的,因为各种鸭子外观都不相同。

现在,新增加一个需求:鸭子要会飞(fly),直接在超类duck中增加,完美!

完美吗?No!有一只橡皮鸭子(洗澡时用的那种)竟然也会飞???所以需要在该类中覆盖超类的fly,如果需求一直变动或新增(比如木头鸭子,不会叫不会飞)时,这对维护代码并不友好

使用接口

那定义两种接口,FlyableQuackable呢?

image.png 这样的问题在于,所有需要的类都要实现该接口,代码会一直重复,所以也不可行

软件开发真理

软件开发唯一不变的是变化

不论最初设计的多好,随着需求变动,总需要成长与改变,所以设计时不仅考虑当前功能的实现,更要考虑后续的维护与扩展

策略模式

找出应用中可能需要变化之处,把他们独立出来,不要和不需要变化的代码混在一起

Duck除了飞和叫之外,其他部分目前不需要经常变化和修改,所以可以不做太多处理

针对接口编程,而不是针对实现编程

将fly和quack两种行为独立出来,建立一组新类来代表每个行为:FlyBehaviorQuackBehavior

image.png

多用组合,少用继承

这样子,飞行和叫可以被其他对象复用(“有一个”行为,而不是“是一个”行为)

Duck类中加入两个实例变量,由每个鸭子对象实例化时动态设置引用(目前还是针对实现编程)

同时这样有个好处,在运行时可以自由改变鸭子的这两种行为(重新赋值)

image.png

与最初开始时的设计相比,对于维护与修改已经有了很大帮助

结尾思考

考虑下面这些类的继承、接口关系。这个还是很简单的,同时对于游戏中更换武器的实现,有了初步的了解吧(属于游戏党的小快乐了)

image.png

设计原则清单

  • 找出应用中可能需要变化之处,把他们独立出来,不要和不需要变化的代码混在一起
  • 针对接口编程,而不是针对实现编程
  • 多用组合,少用继承

学习来源:《Head First 设计模式(中文版)》第1章