(转载)设计模式之-策略模式(Strategy)
原文:http://blog.sina.com.cn/s/blog_48df74430100t2m7.html
前言
部门组织培训,《Effective Java》,每人每天给大家讲解一节。但十个同事就我一个是做.Net开发的,所以每回我就是听众,前两天的一节是《用函数对象表示策略》,讲的非常短频快,但下来我的感触颇多,对代码不再有当初的激情了,但总想把平时经常用到的,别人已经总结归纳的用文字记录下来,好记性不如烂笔头,只有记录下来的才是属于自己的。于是决定从本篇开始我的设计模式之旅,这个系列3年前就有总结的想法,但一再找各种理由推托,就像戒烟一样,希望对自己来说现在不算太晚。
从Justin老兄的博客看到经典“鸭子模式”的例子,对我的启发非常大,也是参照他的例子自己胡思乱想了“飞机模式”,跟鸭子模式很像,其实也就是自己编个故事给自己听,然后从故事里能总结出来一些道理就好。鸭子模式原文地址:http://www.cnblogs.com/justinw/archive/2007/02/06/641414.html
从简单的例子开始
话说中东X国空军指挥部使用OO语言开发一款作战飞机管理系统,想把所有飞机管理起来。刚开始由于飞机数量有限,仅拥有为数不多的几架从美俄进口的战斗机,于是开发人员构建了如下的类结构:
如图所示,在“飞机”基类里实现了公共的“飞行”和“加油”方法,而“F22战斗机”和“猛禽战斗机”可以分别覆盖实现自己的“外型”方法,这样即重用了公共的部分,又支持不同子类的个性化扩展。从目前的情况看,X国国防部很满意!
过了一段时间,世界石油价格飙涨,X国高层觉得是时候再添置一批运输机了,以配合地面部队的物质补给,于是X国又采购了一批大力神运输机,空军指挥部的开发人员扩展了他们的类结构:
恩,目前仍然不错,开发人员觉得自己的设计非常棒,甚至国防部还将这个项目纳入了X国国家9527火炬计划!
然而世界局势变幻莫测,X的邻国Y国早对X的石油资源垂延三尺,终于有一天按奈不住冲动,一拥而上......大兵压境,X国十万火急向美俄购入一批导弹来武装“F22”和“猛禽”战斗机,开发人员丝毫不敢怠慢,连夜修改了他们的设计:
第二天,有了攻击系统的X国空军准备大规模反攻时,悲剧发生了,之前按战斗机数量采购的导弹居然不够用,有一半以上的战斗机在出发前居然未能装弹。国防部长来到现场发现:每架运输机机翼上居然捆了两枚价值100万美元的“小牛”空对地导弹。
当天损失惨重,总统下了最后通牒:马上修改你们的系统,三天内如果修改不好,所有人都去挖煤!
顶着压力,开发人员终于冷静下来找到了原因,原来在“飞机”基类里增加的“攻击”方法,也同样被子类“大力神运输机”给继承了,而基类里的“攻击”方法包括了装弹步骤,所以就有了运输机悬挂空对地导弹的一幕。那么该怎么办呢?有人提议:能不能在“大力神运输机”里把“攻击”方法重写一下?让它什么都不做,不就行了吗?但马上有人反对,那“F22战斗机”和“猛禽战斗机”是不是也要重写?并且以后如果再增加其它类型的教练机、预警机、运输机,是不是都要重写“攻击”方法?这太麻烦了,而且非常混乱。
大家很困惑,为什么屡试不爽的继承,在系统扩展的时候,无法很好地支持重用呢?最后经过反复讨论,决定使用接口,设计如下:
但空军指挥部马上否决了这个设计:“你们难道希望所有载有导弹的飞机都去重复实现这个方法吗?现在我们飞机少还好说,但有不久后我们有成千上万架战斗机的时候怎么办?如果导弹系统要做一点修改,难道要重复修改上万遍吗?你们是不是疯啦?”
策略模式前奏
如果你是X国的开发人员,你会怎么做?我们知道,并不是所有飞机都能攻击,所以继承不是正确的方法。虽然上面使用“攻击接口”可以解决部分问题(不再给运输机装上“小牛”空对地导弹),但是这个解决方案却彻底破坏了重用,它带来了另一个噩梦----维护!
要解决这个问题,我们必须回到设计模式的第一个原则:
Identify the aspects of your application that vary and separate them from what stays the same.(找到系统中变化的部分,将变化的部分同其它稳定的部分隔开)
什么意思?打个简单的比方,你电脑上有主板有硬盘,主板跟硬盘是可以很方便拆分开的吧。你今天可以用100G的硬盘,明天可以换500G的硬盘,硬盘就是变化部分,它根据用户需求随时都能调整;而主板上的南北桥芯片你能更换不?也许有强人能做到,但起码厂家的设计是不让你轻易更换的吧,所以这就是稳定部分。我们可以发现,其实设计模式不只针对软件,它随处可见。
Program to an interface, not an implementation.(面向接口编程,而不要面向实现编程)
这条原则应该是经常看见,它跟面向对象里的“多态”紧密相连,什么意思?我们还是继续上面电脑主板的例子,其实主板开发商早已把“面向接口”发挥的淋漓尽致了。拿主板上的USB口来说,USB口可能外接数码相机,可能外接打印机,外接键盘鼠标,外接手机,外接五花八门各种各样已经有的和未来会出现的设备。如果主板厂家为每种设备都实现一套独立的交互程序,那后果是灾难性的。于是主板厂家们使用了面向接口开发,接口早期由像IBM这样的大厂商制订,后来由一些标准化组织接管,他们在接口里声明了所有用到的标准,比如数据的传输封装格式,接口的型状,接口能接受的电压等等,主板厂家们只按照接口标准来开发自己的主板,而不用关心接口另一端连接的是什么设备。
策略模式登场
The Strategy Pattern defines a family of algorithms,encapsulates each one,and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.(策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们可以相互替换。策略模式让算法独立于使用它的客户而独立变化。)
X国使用策略模式后的类结构图如上。
1、将变化部分跟稳定部分分离开:飞机一定是要飞行的,所以“飞行”是稳定部分;飞机一定得加油,所以“加油”是稳定部分;飞机一定会有外型,就算是隐形飞机也不例外,所以“外型”也是稳定部分。而“攻击”则有的飞机有,有的飞机没有,比如战斗机能攻击而运输机不能,所以“攻击”属变化部分,需要将其与稳定部分分离开。
2、单单分离开只是策略模式的一部分,还需要将变化部分细化、整理和抽象,此时,面向接口会是理想选择。
不谈理论,还是用实例继续,OK,经过一段时间实战,X国的空军指挥官们发现了一个奇怪的现象:苏制F22战机每次作战几乎毫发无伤,而美制的猛禽战斗机和大力神运输机却每每损失惨重。经过反复研究,他们终于发现原来F22战机拥有性能强悍的雷达系统,而美制飞机的雷达全部是Made In China,200米范围以外根本侦测不到敌机。于是他们决定花重金将所有美制飞机的雷达更换为以色列的天网系列。这回开发人员很轻易扩充了他们的另一策略:
从类图中可以发现,每个策略均是独立的,各种类型的飞机可以任意添加、删除和组合各种不同的策略。
对策略模式的总结
通过X国的模拟实例可以发现,继承的功能确实很强大,但是也存在诸多问题,因为它违背了封装原则。只有当子类和父类之间确实存在子类型关系时,使用继承才是恰当的。即便如此,如果父类不是为了继承而设计的,那么继承将会导致脆弱性,所以可以用复合来代替继承,这一点在策略模式中尤其重要。同时这也是本文的最后一个非常重要的设计原则:Favor composition over inheritance.(优先使用对象组合,而非类继承)
(转载)设计模式之-策略模式(Strategy)的更多相关文章
- 乐在其中设计模式(C#) - 策略模式(Strategy Pattern)
原文:乐在其中设计模式(C#) - 策略模式(Strategy Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 策略模式(Strategy Pattern) 作者:webabc ...
- 反馈法学习设计模式(一)——策略模式Strategy Pattern
简介(Introduction) 之前学习Java8实战时,遇到一个很好的策略模式示例.便想着借着这个示例结合反馈式的方法来,学习策略设计模式,也以便后面反复琢磨学习. 首先我们通过练习,逐步写出符合 ...
- JAVA设计模式之策略模式 - Strategy
在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改.这种类型的设计模式属于行为型模式. 在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 ...
- 8.6 GOF设计模式四: 策略模式… Strategy Pattern
策略模式… Strategy Pattern 在POS系统中,有时需要实行价格优惠, 该如何处理? 对普通客户或新客户报全价 对老客户统一折扣5% 对大客户统一折扣10% 注:课件 ...
- 二十四种设计模式:策略模式(Strategy Pattern)
策略模式(Strategy Pattern) 介绍定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换.本模式使得算法的变化可独立于使用它的客户. 示例有一个Message实体类,对它的操作有 ...
- [设计模式] 21 策略模式 Strategy
在GOF的<设计模式:可复用面向对象软件的基础>一书中对策略模式是这样说的:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换.该模式使得算法可独立于使用它的客户而变化. 策略模 ...
- 大熊君说说JS与设计模式之------策略模式Strategy
一,总体概要 1,笔者浅谈 策略模式,又叫算法簇模式,就是定义了不同的算法,并且之间可以互相替换,此模式让算法的变化独立于使用算法的客户. 策略模式和工厂模式有一定的类似,策略模式相对简单容易理解,并 ...
- 设计模式之策略模式Strategy
/** * 策略设计模式 * 策略模式:定义一系列的算法族,使他们之间可以相互转换,动态的改变其行为. * 问题:设计一个鸭子模拟游戏. * 现在有一群鸭子: * ①这些鸭可以有飞的行为(分为快和慢) ...
- 大话设计模式之策略模式(strategy)
策略模式:它定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化不会影响使用算法的用户. 针对商城收银模式,打折,返现促销等的例子: 打折还是促销其实都是一些算法,可以用工厂模式来 ...
- 设计模式 笔记 策略模式 Strategy
//---------------------------15/04/28---------------------------- //Strategy 策略模式----对象行为型模式 /* 1:意图 ...
随机推荐
- VS2010编译Boost 1.56
(1)首先下载源代码:http://softlayer-dal.dl.sourceforge.net/project/boost/boost/1.56.0/boost_1_56_0.zip 解压到某个 ...
- POJ 2976 Dropping tests (0/1分数规划)
Dropping tests Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 4654 Accepted: 1587 De ...
- SpringBoot配置属性之其他
SpringBoot配置属性系列 SpringBoot配置属性之MVC SpringBoot配置属性之Server SpringBoot配置属性之DataSource SpringBoot配置属性之N ...
- iOS 一个小动画效果-b
近期工作不忙,来一个需求感觉棒棒的,是一个比较简单的页面,如下图(图1) 图1 应该很简单吧,没什么大的功能,就是一个展示,一个拨打电话,拨打电话不需要说,几行代码搞定,基本UI也不用说了,刚培训完的 ...
- Swift 类型检查与类型转换
前言 在 Swift 语言中一般使用 is 关键字实现类型检查,使用 as 关键字实现类型转换,除此之外还可以通过构造器和方法来实现类型转换. 1.类型检查 1.1 使用 is 检查 类型检查操作符 ...
- 第一篇:初识ASP.NET控件开发_第二节:HelloWorld
1)步骤一:新建类库项目:Controls,创建新解决方案:CustomLibrary 2)步骤二:在类库项目中添加“ASP.NET服务器控件”新建项:RenderHelloWorld.cs (也可以 ...
- 用 Fiddler 来弥补 Chrome Network 的小缺点
由于经常要查看后端的接口详情,但Chrome控制台的Network并不会全显api路径,而且每次需要先启动控制台,再进行请求才能记录到.大多数情况下都是要刷新页面,这会浪费很多时间. 还不如开一个 F ...
- MSSQL2005:“超时时间已到。在操作完成之前超时时间已过或服务器未响应”
1.今天在整合项目中有这样一个需求,就是要改变以存在表字段的文本的大小,如把char(15)改成varchar(50). 2.此时以存在表已有1885742条数据,在直接下面进行调用 ALTER TA ...
- 使用mysql innodb 使用5.7的json类型遇到的坑和解决办法
---------------------------------------------- #查询JSON的某个字段 select data -> '$.Host' from temp #创建 ...
- 有关 Windows 10 中“适用于 Linux 的 Windows 子系统(Beta)”
1.如何启用?(未来应该可从应用商店中直接安装) 在"控制面板"的"启用或关闭 Windows 功能"中进行勾选安装.(安装完成后需要重新启动) 2.然后呢? ...