设计模式:策略模式

在上一个章节有提到设计模式的原则,这一章主要会提到以下三点:

1.找出程式会变的东西,把其和不会变的部分分开。

2.针对介面写程式,而不是针对实作写程式。

3.多用组合,少用继承。

假设我们正在开发游戏一个游戏,并且以物件导向的方式创造了一个角色:鸟(Bird),让其他种鸟的角色可以继承:
http://img2.58codes.com/2024/20157184SvX920qidZ.png

此时,为了增加角色功能的丰富程度,我们需要添加了飞行功能(fly),所以把飞行功能增加到鸟的类别上,让继承鸟类别的角色都可以一併继承这个功能。

http://img2.58codes.com/2024/201571843fNAA6UHD0.png

过了一段时间,我们发现了一个问题:当我们创建了新角色鸵鸟(ostrich)的时候,它竟然会飞!这似乎并不符合常理。
http://img2.58codes.com/2024/20157184IHg6KvGC44.png

所以为了修改这个错误问题,把鸵鸟的飞行功能覆写(override)掉,应该就解决了...
http://img2.58codes.com/2024/20157184TS4KH5xLxu.png

过了一段时间,当新角色玩具鸟(ToyBird)出现时又遇到相同的问题,它既不会飞,也不会叫,所以再次覆写飞与叫的方法:
http://img2.58codes.com/2024/20157184sZEmQbMYhJ.png

此时我们觉得,每次建立一个新角色,就要重新检查继承而来的方法是否合理,并且视情况覆写,这个做法有点糟,
这时候我们想到,可以把飞(fly)跟叫(Scream)拿出来,变成介面,让会飞或会叫的鸟去实作那个介面就好,不会飞或叫的角色就可以不用实作。
http://img2.58codes.com/2024/20157184EDiSotgc1c.png

没想到,过了一阵子,我们发现这样的做法,会让我在创造新的角色时,有可能需要写出跟其他角色重複的程式码:因为很多角色的飞行模式是一样的!更糟的是,一旦我在游戏内修改一种飞行模式的定义,我就必须确认所有跟这个飞行模式相关的类别并修改他们的程式码。

怎么办?这个时候我们需要从第一个设计模式原则下手:

1.找出程式会变的东西,把其和不会变的部分分开。
把会变的部分封装起来,之后如果需要进行修改,就针对要变的部分进行修改,使其不会影响其他部分。

从上面的案例我们可以看到,会变的部分就是两种行为:飞与叫,因此,我们需要建立两组类别,把他跟原来鸟的类别分开。每一组类别都去实作不同的行为。

http://img2.58codes.com/2024/20157184uvjLK7Aw7v.png

http://img2.58codes.com/2024/20157184X8WSu300M7.png

接着,我们可以在角色初始化的时候,指派这些行为给不同种类的鸟,甚至可以建立SetBehavior的方法,来在程式执行的期间,可以动态的调整这些角色的行为。

http://img2.58codes.com/2024/20157184dy07fMJgDd.png

public class ToyBird : Bird{  public ToyBird() {   //不会飞也不会叫   FlyBehavior = new FlyWithNothing();   ScreamBehavior = new MuteScream(); }}
//传入新的飞行行为,替换旧有行为public void SetFlyBehavior(FlyBehavior flybehavior){ FlyBehavior = flybehavior;}//传入新的叫法,替换旧有行为public void SetScreamBehavior(ScreamBehavior screamBehavior){  ScreamBehavior = screamBehavior;}

这个做法与之前的作法差别在于:之前的行为都是为了鸟这个超类别,或是鸟的子类别去量身打造的实作方法,因此这些行为都依赖一个实作,导致需要改变行为的时候,只能透过修改程式来达成,且会随着类别扩大而造成维护上的困难。

在新的设计中,鸟的子类别会使用介面所代表的两种行为。而这些行为的实作,是单纯为了实作飞(fly)跟叫(Scream)的具体行为,也就不会被限制在鸟的子类别里面。

而这样的设计,就符合了设计原则的第二点:
2.针对介面写程式,而不是针对实作写程式。
http://img2.58codes.com/2024/20157184voqJ5FjE8Y.png

此外,把类别组合起来的方式,就是组合,用组合建立起的系统可以将行为进行封装,并且可以在执行起改变行为,我们可以从此看到第三种原则:

3.多用组合,少用继承。

以上就是策略模式的运用,策略模式的定义就是去封装一系列的演算法(可以把那些实作的行为视为演算法),并且在不影响用户端的情境下替换并改变演算法。

Reference:
深入浅出设计模式-设计模式入门, 2/e (Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software, 2/e)


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章