在前段时间呢陆陆续续的更新了一系列关于重构的文章。在重构我们既有的代码时,往往会用到设计模式。在之前重构系列的博客中,我们在重构时用到了“工厂模式”、“策略模式”、“状态模式”等。当然在重构时,有的地方没有点明使用的是那种设计模式。从今天开始,我们就围绕着设计模式这个主题来讨论一下我们常用的设计模式,当然“GoF”的23种设计模式不会全部涉及到,会介绍一些常见的设计模式。在接下来我们要分享的设计模式这个系列博客中,还是以Swift语言为主来实现每种设计模式的Demo。并且仍然会在GitHub上进行Demo的分享,希望与大家相互交流,相互学习,有不足之处还望批评指正。

今天博客的主要思路是先围绕着“穿越火线”中的角色与武器的关系,通过策略模式来设计实现这种关系,整体的来整体感受一下“策略模式”的优点。然后再参考《Head First Design Patterns》这本书中的鸭子的示例,来一步步使用Swift来实现策略模式的案例。当然我们只是参考《Head First Design Patterns》中的示例,本篇博客中的示例与其中的示例还是有所区别的。大部分设计模式的案例都是使用Java实现的,我们依然会使用Swift来实现。还是那句话,设计模式是针对面向对象编程语言的,而不是针对某一种编程语言,Swift是面向对象的语言,所以设计模式用于Swift编程中是没有问题的。废话少说,进入今天博客的主题。

一、穿越火线中的“策略模式”(Strategy Pattern)

当然,这个示例是我YY出来的示例,不是“穿越火线”这个游戏的设计方案呢。说到"穿越火线"如果你没有玩过,那应该听过吧,就是“CrossFire”。我平时不怎么玩游戏,穿越火线之前体验过,不过只有被爆头的份儿。听说那些游戏玩家现在不怎么玩儿“CF”啦,改玩儿Dota,LOL啦,真的是这样吗?我个人对于游戏而言是外行了,不过玩个超级玛丽、魂斗罗、植物大战僵尸、节奏大师还是可以的(坏笑)。

言归正传,今天我们就模拟穿越火线中角色和武器的关系,使用“策略模式”来实现。首先我们先分析一下这个场景,穿越火线中角色分为不同的等级,也就是“军衔”了,简单的说几个吧,由高到底对应着“军师旅团营连排小工兵”,上面的是组织,军衔莫过于各种级的士官,少中上尉,少中上校,少中上将(应该对吧,本人不太专业呢,不过用于咱们要实现的例子是够了)。我虽然不怎么会打CF,可是我会玩军棋呢。

我是不是刷知乎刷多了,不能在这儿“一本正经的胡说八道”了。言归正传,不同的角色所配备的武器装备也不同,等级越高所使用的武器装备也就越厉害。我们如何使用面向对象来表达这种角色与武器之间的关系呢?我们先看一下下方的类“类图”。

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

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

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

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

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

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

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

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

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

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

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

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

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

本来想着在结合着《Head First Design Patterns》这本书中的鸭子示例在聊一下“策略模式”呢,由于篇幅有限,今天的博客到这儿吧。对于“策略模式”上面是一个完整的示例。

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

设计模式(一):“穿越火线”中的“策略模式”(Strategy Pattern)的更多相关文章

  1. 乐在其中设计模式(C#) - 策略模式(Strategy Pattern)

    原文:乐在其中设计模式(C#) - 策略模式(Strategy Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 策略模式(Strategy Pattern) 作者:webabc ...

  2. 反馈法学习设计模式(一)——策略模式Strategy Pattern

    简介(Introduction) 之前学习Java8实战时,遇到一个很好的策略模式示例.便想着借着这个示例结合反馈式的方法来,学习策略设计模式,也以便后面反复琢磨学习. 首先我们通过练习,逐步写出符合 ...

  3. HeadFirst设计模式读书笔记(1)-策略模式(Strategy Pattern)

    策略模式(Strategy Pattern): 定义了了算法簇,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户端. 第一个设计原则:找出应用中可能需要变化之处,把他们独立 ...

  4. 8.6 GOF设计模式四: 策略模式… Strategy Pattern

    策略模式… Strategy Pattern  在POS系统中,有时需要实行价格优惠, 该如何处理?  对普通客户或新客户报全价  对老客户统一折扣5%  对大客户统一折扣10%  注:课件 ...

  5. 二十四种设计模式:策略模式(Strategy Pattern)

    策略模式(Strategy Pattern) 介绍定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换.本模式使得算法的变化可独立于使用它的客户. 示例有一个Message实体类,对它的操作有 ...

  6. 设计模式 - 策略模式(Strategy Pattern) 具体解释

    策略模式(Strategy Pattern) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26577879 本文版权全 ...

  7. 十一个行为模式之策略模式(Strategy Pattern)

    定义: 定义一系列的算法,将每一个算法封装起来,并使它们之间可以相互替换,让算法具有可扩展性和对立性. 结构图: Context:环境类,算法的使用者.对外提供了算法使用的接口,并且持有一个抽象算法类 ...

  8. 设计模式——策略模式(Strategy Pattern)

    写在前面: 直接将书中的例子用来作为记录自己学习的成果,不知道这样好不好,如果给原作者带来什么不利的影响不妨告知一声,我及时删掉. UML图: 抽象策略:Strategy package com.cn ...

  9. C#设计模式——策略模式(Strategy Pattern)

    一.概述我们来实现一个企业的工资系统,该企业中不同级别的员工工资算法都不相同,针对该问题,最容易想到的莫过于在代码中堆积一大堆if…else…语句或者是switch…case…语句.如果该企业中不同级 ...

随机推荐

  1. Fis3的前端模块化之路[基础篇]

    Fis3版本:v3.4.22 fis3是一个构建工具 解决前端开发中自动化工具.性能优化.模块化框架.开发规范.代码部署.开发流程等问题. 安装 npm install -g fis3 运行 fis3 ...

  2. 奇异值分解(SVD)原理与在降维中的应用

    奇异值分解(Singular Value Decomposition,以下简称SVD)是在机器学习领域广泛应用的算法,它不光可以用于降维算法中的特征分解,还可以用于推荐系统,以及自然语言处理等领域.是 ...

  3. 笔记:Binder通信机制

    TODO: 待修正 Binder简介 Binder是android系统中实现的一种高效的IPC机制,平常接触到的各种XxxManager,以及绑定Service时都在使用它进行跨进程操作. 它的实现基 ...

  4. 【翻译】MongoDB指南/CRUD操作(二)

    [原文地址]https://docs.mongodb.com/manual/ MongoDB CRUD操作(二) 主要内容: 更新文档,删除文档,批量写操作,SQL与MongoDB映射图,读隔离(读关 ...

  5. Hawk 7. 常见问题

    本页面您可以通过关键字搜索来获取信息. 理性使用爬虫 爬虫是一种灰色的应用,虽然作为Hawk的设计者,但我依然不得不这么说. 各大网站都在收集和整理数据上花费了大量的精力,因此抓取的数据应当仅仅作为科 ...

  6. 如何定位Oracle数据库被锁阻塞会话的根源

    首先再次明确下,数据库因为要同时保证数据的并发性和一致性,所以操作有锁等待是正常的. 只有那些长时间没有提交或回滚的事物,阻塞了其他业务正常操作,才是需要去定位处理的. 1.单实例环境 2.RAC环境 ...

  7. await and async

    Most people have already heard about the new “async” and “await” functionality coming in Visual Stud ...

  8. PhpStorm和WAMP配置调试参数,问题描述Error. Interpreter is not specified or invalid. Press “Fix” to edit your project configuration.

    PhpStorm和WAMP配置调试参数 问题描述: Error. Interpreter is not specified or invalid. Press “Fix” to edit your p ...

  9. 屌丝giser成长记-大学篇

    作为一名屌丝giser的我,刚接触gis专业是2007年的大一,好悲催,当时gis这个专业是被调剂的,我压根都不知道gis为何物,那时候gis冷门的一逼,报名这个专业的寥寥无几.记得那时候得知被调剂到 ...

  10. RMS去除在线认证

    在微软 OS 平台创建打开 RMS 文档如何避免时延 相信我们在企业内部的环境中已经部署了微软最新的OS平台,Windows 7和Windows 2008 R2,在这些OS平台上使用IRM功能时,您有 ...