144540zztwbbtt7xt2xbxz.png
  上面是一个简化的类“类图”,上面这种形式可以表达我们之前的那种场景。“军人”是一个父类,其他具体等级的军官都继承自“SuperClass”。那么问题来了,在上面那种模式下,如果只有“少尉”和“中尉”配备某种武器,其他军官不配备,我们就要在“少尉”和中尉的类中分别添加要实现的武器,那么这样会产生冗余的代码。还有个问题是上面的设计形式不利于扩展,比如“少尉”也要配备狙击,岂不是得从“中尉”中的狙击的方法复制到“少尉”中。这样也会产生重复代码的。那么我们该怎样去解决这个问题呢?

  有童鞋说了,在Swift中的Protocol(协议,也就是Java中的接口)可以提供默认的实现。也就是声明一个protocol,然后通过extension来为协议添加默认实现,只要是类遵循该协议,那么这个类就拥有了这个默认实现(当然,Java中的接口是不能通过后期的延展来为其添加默认实现的)。如果在Swift中使用接口的默认实现的话,如果要对上述军官扩充装备的话,设计中的类“类图”(不是类图,但与类图相似)实现如下所示:

144540imzgt3ogk8w43kia.png
  上面这种设计模式虽然不会产生重复的代码,但是如果给“军官”添加的武器过多的话,那么会导致相应的类中实现的接口过多,这并不是我们想要的。下方将会给出一个良好的解决方案,也就是使用策略模式。

  二、使用“策略模式”(Strategy Pattern)对上述关系进行设计

  “策略模式”的定义大概是:策略模式,将不同的策略(算法)进行封装,让他们之间可以相互的替换,此模式让策略的变化独立于使用策略的用户。在设计模式中有不同的设计原则,其中有一条就是“找出程序中可能需要变化的地方,并且把它吗独立出来,不要和不变的代码混在一起”。根据这条设计原则,然后结合着上述示例不难分析出来,在上述示例中,使用军官使用的不同武器是可以变化的,使用不同的武器正是采取不同的策略呢。

  所以经过上述讨论,我们可以使用“策略模式”来重新设计上面的结构。简单的说就是把变化的“武器”部分进行提取,然后在军官中进行使用,不同的军官可以采取不同的策略,并且可以随时替换。下面是我们使用“策略模式”重新设计后的关系,具体请看下图。

144541uxmbbqv4mxmvjjja.png
  在上面的类“类图”中我们对可变的“武器策略进行了提取”。我们使用了WeaponBehavior协议来规定武器的策略,使得不同的武器对外有统一的接口,在此就是使用武器,也就是开火。不同的武器使用不同的的“开火策略”,但是对外的接口都是一样的。设计原则中有一条是“面向接口编程,而不是面向实现编程”。这里所指的接口可以是协议,可以是抽象类,也可以是超类,其实就是利用面向对象的“多态”特性。上面的红框中实现的就是所有不同的策略。

  而绿框中是我们的用户,也就是军官的定义,是我们不变的部分。在军官中也有一个基类,在基类中定义了军官的共性,其中依赖于“武器策略”的接口。在军官超类中使用“武器策略”的协议声明了一个对象,该对象就是该军官所采取的武器策略。在军官的超类中可以通过setWeapon()方法采取不同的策略,其中fire()方法就是使用该“武器策略”进行开火。在具体的军官中的changeXXX()方法就是调用setWeapon()方法进行策略切换的方法。具体内容请看下方的具体实现。

  三、上述“策略模式”(Strategy Pattern)的具体实现

  上面给出了“武器策略模式”的个个部分之间的关系,并给出了相应的解释。如果对此你感觉到抽象的话,那么我们接下来就用相应的Swift代码去实现上述示例。也就是将上面的理论部分进行具体实现,当然在此我们用的是Swift语言,但是,你完全可以使用其他的面向对象编程语言。下面就是我们具体的代码实现。

  下方就是我们对“武器策略”的实现,红框中对应的就是上面图中的WeaponBehavior(协议)接口,下方绿框中就是不同武器的策略,每个武器策略都遵循了WeaponBehavior协议。并且实现了相应的useWeapon()方法。

144541k81prmx7f7zppaxm.png
  对“武器策略”模块实现完毕后,接下来我们就得实现军官模块了。也是根据上面我们所画的“模式结构图”来实现我们的“军官模块”,下方Character就是所有军官的基类,其中默认的武器策略weapon就是(PistolBehavior),其中有设置策略和改变策略的方法,并且还有使用策略的方法(fire())。下方的红框就是实现的不同的军官了,不同的军官可以有不同的切换策略的方法。具体如下所示:

144542sxgff3xzs91qsnw6.png
  上面就是我们全部实现的代码,下方是我们的测试用例和输出结果。下方我们创建了一个“中尉”军官----lieutenant,军官默认的是开的。但是可以调用相应的changeXXX()方法来切换武器策略。开时,发现火力不行,然后就调用changeHK()方法切换到HK48。这种关系使用“策略模式”就比较灵活,并且便于扩展。比如中尉现在也要配备大狙,因为现在已经有大狙这个武器策略了,所以我们现在只需在中尉中添加相应的change方法,传入大狙的武器策略即可,具体的就不在演示了。

144542g2sltymthyygohtt.png
  上述代码gitHub分享地址为:https://github.com/lizelu/DesignPatterns-Swift

  相关阅读游戏编程设计模式-state

锐亚教育

锐亚教育,游戏开发论坛|游戏制作人|游戏策划|游戏开发|独立游戏|游戏产业|游戏研发|游戏运营| unity|unity3d|unity3d官网|unity3d 教程|金融帝国3|8k8k8k|mcafee8.5i|游戏蛮牛|蛮牛 unity|蛮牛