深入浅出策略模式
- 格式:doc
- 大小:9.21 MB
- 文档页数:11
策略模式详解
策略模式是一种行为型设计模式,它定义了一系列算法,并将每一个算法封装起来,使它们可以相互替换。
策略模式使得算法可以独立于使用它的客户端而变化。
策略模式适用于那些需要使用多种算法的问题。
由于每种算法都有其特殊的用途,因此客户端需要根据当前的情况选择最合适的算法。
在这种情况下,策略模式提供了一个灵活且可扩展的框架,使得算法的选择和使用变得简单且易于维护。
在策略模式中,有三个主要的参与者:
1. Strategy:策略接口定义了所有算法的公共接口,客户端通过这个接口来调用算法。
这样,客户端就不需要关心具体的算法实现,只需要根据需要选择相应的策略即可。
2. ConcreteStrategy:具体策略类实现了策略接口,并提供了具体的算法实现。
每个具体策略类都代表了一种特定的算法。
3. Context:上下文对象负责维护策略对象的实例,并根据需要切换不同的策略。
上下文对象通常会根据客户端的请求选择合适的策略对象,并将这个策略对象传递给客户端。
策略模式的优点在于它能够提供一种灵活且可扩展的解决方案,使得算法的选择和使用变得简单且易于维护。
由于策略对象是独立的,因此可以很容易地添加新的策略,而不需要修改现有的代码。
此外,策略模式还可以提供一种替换算法的方式,使得系统能够根据需要进
行动态的调整。
总之,策略模式是一种非常有用的行为型设计模式,它能够提供一种灵活且可扩展的解决方案来解决那些需要使用多种算法的问题。
java 策略模式应用场景策略模式是一种行为模式,它定义了一系列算法并将每个算法封装在可互换的对象中,使得它们之间可以相互替换。
在实际开发中,策略模式有广泛的应用场景,以下是一些常见的场景:1.交通工具出行方式选择在交通工具中,不同的交通工具具有不同的出行方式,如步行、骑车、开车等。
每个出行方式都有自己的特点和适用场景。
使用策略模式可以将每个出行方式抽象成一个策略类,通过选择不同的策略实现类来进行出行方式的选择。
2.游戏中的角色技能选择在游戏开发中,角色通常会拥有多种技能,玩家可以根据不同的战斗情况选择合适的技能。
使用策略模式可以将每个技能抽象成一个策略类,通过选择不同的策略实现类来实现技能的选择和释放。
3.支付方式选择在电商应用中,用户可以选择不同的支付方式进行支付,如支付宝、微信支付、银联支付等。
每种支付方式都有自己的支付流程和手续费等特点。
使用策略模式可以将每种支付方式抽象成一个策略类,通过选择不同的策略实现类来进行支付方式的选择和支付操作。
4.数据校验策略在表单验证、数据校验等场景中,需要对输入的数据进行校验,如判断输入的字符串是否符合要求、判断手机号码格式是否正确等。
使用策略模式可以将每种校验规则抽象成一个策略类,通过选择不同的策略实现类来进行数据校验。
5.优惠活动策略在电商平台中,经常会有各种优惠活动,如满减、折扣、赠品等。
每种优惠活动都有自己的优惠规则和适用条件。
使用策略模式可以将每种优惠活动抽象成一个策略类,通过选择不同的策略实现类来进行优惠活动的选择和计算。
6.算法选择在算法求解问题中,往往会有多种不同的算法可以选择,如排序算法、搜索算法等。
每种算法都有自己的时间复杂度和空间复杂度等特点。
使用策略模式可以将每种算法抽象成一个策略类,通过选择不同的策略实现类来进行算法的选择和使用。
7.缓存策略选择在系统开发中,常常需要对数据进行缓存以提高系统性能。
不同的缓存策略有不同的缓存策略,如FIFO(先进先出)、LRU(最近最少使用)等。
策略模式实际用法案例
以下是 6 条关于策略模式实际用法案例:
案例一:想想看,咱平时网上购物选快递的时候,这不就是策略模式嘛!你可以根据速度快慢选择顺丰,要是想省点钱呢,就选那个比较便宜的快递。
这就像打仗的时候,根据不同情况派出不同的战术部队一样,牛不牛?
案例二:嘿,就说游戏里选择不同角色的技能升级策略,那也是典型的策略模式呀!比如战士可以重点升级力量,法师呢就着重提升魔力。
这不就跟咱吃东西挑自己喜欢的口味一样嘛,各有各的选法,超有意思!
案例三:你知道吗,公司制定市场推广策略也能用策略模式。
遇到不同的目标客户群体,就推出不同的方案。
就好比医生对症下药,病重的药量就重点,症状轻点的药量就轻点,多灵活!
案例四:哎呀呀,选交通工具也可以用策略模式呀!着急的时候就打车走,不着急还想看看风景就坐公交慢慢晃悠。
这就好像在人生路上,根据不同的情形选择不同的走法一样,多妙啊!
案例五:讲真的,健身的时候选择不同的锻炼方式也类似策略模式呢。
想减肥就多做有氧运动,想增肌就多做力量训练。
这不就是根据自己的目的去挑选最合适的办法吗,厉害吧!
案例六:再例如,学习不同学科的时候采用不同的学习方法,这也是策略模式的体现呀!数学可能需要多做题,语文要多阅读积累。
这不跟钥匙开锁一样,得用对钥匙才能打开知识的大门呀,是不是很神奇?
我的观点结论:策略模式真的无处不在,它让我们在各种情况下都能做出最适合自己的选择,真的太重要啦!。
策略模式及优化(本⽂参考了《设计模式之禅》⼀书)何时应该使⽤策略模式?当我们的程序中某些算法需要⾃由切换时⾮常适合使⽤策略模式。
⽐如我们写⼀个计算机程序,⾥⾯必然有加减乘除等等算法,并且这些算法还应该根据客户点击什么运算符号来⾃由切换。
我们就以加减算法的实现为例说明如何使⽤策略模式来优化代码,以及如何优化策略模式。
我们实现计算机的加减算法,最简单的写法应该是这样算法类public class Calculator {public final static String ADD = "+";public final static String SUB = "-";//算法加private static int add(int a,int b){return a + b;}//算法减private static int sub(int a,int b){return a - b;}//计算public static int exe(int a,int b,String exeMethod){switch (exeMethod) {case ADD:return add(a,b);case SUB:return sub(a,b);default:return0;}}}场景类public class Context {public static void main(String[] args) {int a = Calculator.exe(3, 4, Calculator.ADD); //加法运算int b = Calculator.exe(3, 4, Calculator.SUB); //减法运算System.out.println(a+""+b);}}现在我们引⼊策略模式先定义⼀个抽象接⼝public interface Strategy {int exe(int a,int b);}再实现加和减算法//加法public class CalculatorAdd implements Strategy{@Overridepublic int exe(int a, int b) {return a + b;}}//减法public class CalculatorSub implements Strategy{@Overridepublic int exe(int a, int b) {return a - b;}}可以看到,我们每个算法都继承了Strategy接⼝,并且实现的exe()⽅法。
策略模式(Strategy)●策略模式(Strategy Pattern)中体现了两个非常基本的面向对象设计的原则------------封装变化的概念------------变成中使用接口,而不是对接口的实现●面向接口的编程1.策略模式的定义1)定义一组算法,将每个算法都封装起来,并且使它们之间可以互换2)策略模式是这些算法在客户端调用它们的时候能够互不影响的变化2.策略模式的意义1)策略模式使开发人员能够开发出由许多可替换的部分组成的软件,并且各个部分之间是弱连接的关系2)弱连接的特性使软件具有更强的可扩展性,易于维护;更重要的是:它大大提高了软件的可重用性3.策略模式的组成1)抽象策略角色:策略类,通常由一个接口或者抽象类实现,比如:Comparator 2)具体策略角色:包装了相关的算法和行为,比如接口的多个实现类3)环境角色:持有一个策略类的引用,最终给客户端调用的,比如:TreeSet,TreeMap4.策略模式的实现1)策略模式的用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换2)策略模式使得算法可以在不影响到客户端的情况下发生变化。
使用策略模式可以把行为和环境分割开来3)环境类负责维持和查询行为类,各种算法则在具体策略中提供。
由于算法和环境独立开来,算法的修改都不会影响环境和客户端5.策略模式的编写步骤1)对策略对象定义一个公共接口(抽象策略角色)2)编写具体策略类,该类实现了上面的公共接口3)在使用具体策略对象的类中保存一个对抽象策略对象的引用(环境角色)4)在使用策略对象的类中,实现对策略对象的set和get方法(注入)或者使用构造方法完成赋值(客户端)6.参看JDK Collections类的源代码7.策略模式的缺点1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类2)造成很多的策略类8.解决方法采用工厂方法(一种设计模式)。
策略模式以及策略模式与模板⽅法的结合
在上⼀篇中我提到了⽤模板⽅法模式来重构以前写过的代码,在看到的留⾔后,我重新审视了⼀下⾃⼰的代码,到底⽤策略模式呢,还是模板⽅法呢?她们之间有没有共性可以抽取出来?
从策略模式的定义中可以看出,策略模式是对⼀组相似算法的包装,使得算法的实现与算法使⽤环境相隔离,在⽗类中提供算法的统⼀接⼝以供环境对象Context调⽤,以最瘦⼩的策略模式实现来说实际上是不满⾜我的需求的,因为我的算法中还包含更多的⼦操作、⼦流程,⽽这些流程⼜很相象,她们的调⽤逻辑框架也是相象的,怎么办?把这些逻辑直接写在Common接⼝中?重构逻辑?将⼦逻辑独⽴出来给出统⼀定义并由⼦类实现?呵呵!越说越象Template Pattern了。
那么我们就把中的代码重新构造⼀下:
实际上从代码中可以看出,从整体结构上讲应该算是策略模式的应⽤,实现了策略实现与环境的分离,由环境决定采⽤什么策略(当然这也是策略模式的⼀个缺点,环境必须知道所有的策略,并知道应该⽤什么策略),但从策略的统⼀接⼝来说⼜可以说是⼀个模板⽅法,不知道把这个运⽤说成是策略模式和模板⽅法的结合是否牵强?
其实归根结底,在这两种模式的运⽤中最原始的东西是什么?正如在他的中所讲的⼀样,是多态的运⽤。
策略模式的实际应用策略模式是一种常用的设计模式,它可以帮助我们实现在不同情况下选择不同的策略来完成相同的任务。
在实际应用中,策略模式有着广泛的应用场景,例如在电商平台的促销活动中、交通运输系统中的路径规划、游戏中的角色选择等等。
在电商平台的促销活动中,策略模式可以帮助商家根据不同的促销策略来吸引消费者。
例如,商家可以根据消费者的购买历史、购买频率以及消费金额等信息,制定不同的促销策略。
对于新用户,可以提供首次购物的优惠券;对于老用户,可以根据其购买金额给予不同程度的折扣。
通过使用策略模式,商家可以根据不同的情况来选择合适的促销策略,以提高销售额和用户满意度。
在交通运输系统中的路径规划中,策略模式可以帮助用户选择最佳的出行方式。
例如,在一个城市中,用户想要从A地到达B地,可以有多种出行方式,如步行、公交、地铁、出租车等。
不同的出行方式有着不同的时间花费、费用和舒适度等因素。
通过使用策略模式,系统可以根据用户的出行需求和偏好,选择最佳的出行方式并提供最佳的路径规划。
在游戏中的角色选择中,策略模式可以帮助玩家根据不同的游戏情况选择最适合的角色。
例如,在一款多人在线游戏中,不同的角色具有不同的技能、属性和特点,玩家可以根据自己的游戏风格和战术选择合适的角色。
某些角色可能适合近战战斗,某些角色可能适合远程攻击,而某些角色则可能适合辅助和治疗。
通过使用策略模式,玩家可以根据游戏情况和自己的游戏风格选择最佳的角色,以提高游戏体验和胜率。
除了以上应用场景,策略模式还可以应用于许多其他领域,如金融投资中的资产配置、机器人控制中的路径规划、智能家居中的节能调控等等。
通过使用策略模式,我们可以根据不同的情况和需求选择最佳的策略,从而提高系统的灵活性、可扩展性和可维护性。
总结起来,策略模式是一种非常实用的设计模式,它可以帮助我们在不同情况下选择最佳的策略来完成相同的任务。
在电商平台的促销活动、交通运输系统的路径规划、游戏中的角色选择等实际应用场景中,策略模式都发挥了重要的作用。
解释器模式和策略模式的比较解释器模式和策略模式都是常见的设计模式,虽然它们有着不同的应用场景和适用范围,但其实都是基于对象和面向接口的设计思想。
本文将从两个方面来比较这两种模式的差异和使用情况,希望对读者有所启发。
一、解释器模式解释器模式是一个行为型模式,它通过定义语言文法来解释相应的操作,主要用于解决一些相似或重复的问题,如关系型数据库查询。
该模式用于将一个复杂的操作解释为一组简单的操作,并将其封装在一个对象中,以使用不同的参数或上下文来执行解释。
解释器模式的结构包括三个部分:抽象表达式、终结符表达式、非终结符表达式。
其中,抽象表达式定义接口,终结符表达式实现该接口,而非终结符表达式组合终结符和非终结符来实现更复杂的操作。
优点:解释器模式可以非常方便地扩展和改变文法规则,只需要增加相应的终结符和非终结符即可。
同时,由于解释器模式将语法规则的解析和执行分离处理,可以提高代码的可维护性和可读性。
缺点:解释器模式需要解析和编译文法规则,且这个过程需要消耗大量的时间和资源。
此外,由于解释器模式需要对文法规则进行频繁的修改和改变,因此对规则的理解和掌握程度也需要相对较高。
二、策略模式策略模式是一个行为型模式,它通过定义一系列算法或行为来实现相同的操作或目标。
该模式将算法或行为封装在一个对象中,并且可以根据需要动态地改变或添加这些算法。
策略模式的结构包括三个部分:抽象策略、具体策略、环境。
其中,抽象策略定义接口,具体策略实现该接口,而环境则用于调用相应的策略。
优点:策略模式具有很高的灵活性和扩展性,可以根据需要随时添加、修改、删除各种不同的策略,并且不会对其他代码产生影响。
此外,策略模式将每种策略都封装在一个对象中,使得代码更加清晰和易于维护。
缺点:策略模式需要客户端程序员了解每种策略的实现和使用方式,如果不够熟悉可能会导致应用不佳。
同时,策略模式的实现需要对每种策略进行详细的设计和开发,因此代码量相对较大。
应用程序开发的模式和策略随着智能手机和智能设备的普及,应用程序开发成为了一个热门话题。
越来越多的人开始参与到应用程序开发中来,但是,不同的应用程序开发者,往往会使用不同的模式和策略。
本文将探讨应用程序开发的模式和策略,帮助读者更好地了解和掌握这一领域。
第一节:传统的应用程序开发模式在过去,应用程序开发往往是高度专业化的工作。
需要多位专业人员,如软件工程师、项目经理、测试人员等进行协作,完成应用程序开发的不同阶段。
这种传统的应用程序开发模式,被称为瀑布模型。
瀑布模型的主要特征是:开发过程严格分为不同的阶段,每个阶段必须完成后才能进入下一个阶段。
这个过程是线性的,开发人员不允许跳过任何一个阶段。
这种模型被广泛应用于大型软件项目,它强调了文档化、形式化管理和跟踪项目进度的重要性。
然而,这种模式存在一些缺点。
首先,由于各个阶段之间的严格分隔,导致开发周期较为漫长。
此外,一旦进入下一个阶段,上一个阶段的错误也不能轻易修改。
这将导致较高的维护成本和时间成本。
因此,这种模型逐渐被舍弃。
第二节:敏捷开发模式的出现为了应对传统开发模式的缺点,敏捷开发模式应运而生。
敏捷开发模式的主要特征是:开发过程并不是严格的、线性的,而是更加灵活、自由的。
每个阶段都是可变的,开发人员可以随时根据需求进行修改。
注重快速响应和高质量交付的敏捷开发模式,从效率、质量、用户体验三方面对传统瀑布模式进行了全方位的颠覆和优化。
敏捷开发的核心思想是迭代开发和持续交付,它强调多对话和高度沟通的协同工作方式,通过加速开发和版本迭代的速度,不断更新产品的功能与质量。
此外,敏捷开发模式还提供了让普通人可以开发软件的可能性和平台。
例如,很多开源项目都使用了敏捷方法。
通过敏捷开发,开发人员可以更加自由地实现自己的想法,跟进业务需求修改方案,更加顺畅地进行应用程序开发。
第三节:面向对象编程与设计模式面向对象编程是一种面向对象的编程方法,也是目前最为流行的编程方法之一。
模板方法模式和策略模式模板方法模式模板方法模式是一种对对象行为的抽象化,它是将某个对象的行为提取出来,封装在方法中,那么该模式就是将某类的行为的设计抽象化,通过抽象化可以简化该类调用时的复杂度。
模板方法模式定义了一个算法的步骤,并将这些步骤的实现延迟到子类中。
这样,即使子类实现了不同的行为,它们仍然可以按照抽象类中定义的步骤去执行。
模板方法模式有以下几个角色:(1)抽象类:抽象类可以定义算法的步骤,它将每一步定义为一个抽象方法,需要子类去实现,但是它不需要指定算法的具体实现步骤;(2)具体子类:由于算法的具体实现步骤由子类来完成,所以它可以完成算法中与特定操作相关而将封装在抽象类中的步骤,也可以重写父类定义的抽象方法;(3)客户端:通常是主函数,负责创建具体子类的实例,并调用其中的某些方法来实现算法的步骤。
模板方法模式的使用场景(1)在某些业务中,多个子类之间存在大量的公用代码,可以将这些公用的代码放到一个父类的模板方法中,以此来减少代码的重复性;(2)当处理某类型问题时,不同的子类可能会提供不同的解决方案,而抽象类可以把这些解决方案整合到一个模板方法中,从而利用这种抽象性去解决具体的问题。
策略模式策略模式是一种行为设计模式,它定义了可以互换的算法族,并且使它们之间可以相互替换。
该模式使得算法可独立于使用它的客户而变化。
策略模式可以看作是一种用于替换多重条件分支语句的更好方案。
(1)环境类:环境类是一个使用策略类的客户端,它可以对一个策略对象进行配置、用于在运行时选择算法;(2)抽象策略:抽象策略类是一类算法的抽象,功能和接口都可以在该抽象类中定义;(4)客户端:使用环境类的客户端,可以使用不同的算法来实现不同的业务,它可以根据实际情况替换策略。
(1)当一个系统具有多种处理某一个问题的算法,并且客户端需要动态地在这些算法中选择一种解决方案时,可以采用策略模式;(2)当系统需要根据外部条件来选择不同的算法时,可以使用策略模式;(3)当一个对象有很多的行为相似,可以采用策略模式,把相似的行为放到一个策略类中,使结构更加清晰。
深入浅出策略模式一、引子跟不同类型的MM约会,要用不同的方法,有的请电影比较好,有的则去吃小吃效果不错,有的去海边浪漫最合适,但目的都是为了得到MM的芳心……哦……打住!!!其实这也就是对不同情况所采取的不同的策略。
这种情况在实际软件开发中也是经常遇到,那么你是怎么来实现不同的策略的呢?看了策略模式后应该会有一些感想吧!二、定义和结构策略模式(Strategy Pattern)属于对象行为型设计模式,主要是定义一系列的算法,把这些算法一个个封装成拥有共同接口的单独的类,并且使它们之间可以互换。
策略模式使这些算法在客户端调用它们的时候能够互不影响地变化。
这里的算法不要狭义的理解为数据结构中算法,应该理解为不同的业务处理方法。
这种做法会带来什么样的好处呢?它将算法的使用和算法本身分离,即将变化的具体算法封装了起来,降低了代码的耦合度,系统业务策略的更变仅需少量修改。
算法被提取出来,这样可以使算法得到重用,这种情况还可以考虑使用享元模式来共享算法对象,来减少系统开销(但要注意使用享元模式的建议条件)。
先看看策略模式的结构:要使算法拥有共同的接口,就要实现一个接口或者一个抽象类出来才行。
这样结构的轮廓也就出来了,可用简单的类图来表示它们之间的关系:策略模式由三个角色组成:1)算法使用环境角色:算法被引用到这里和一些其它的与环境有关的操作一起来完成任务;2)抽象策略角色:规定了所有具体策略角色所需的接口。
在java它通常由接口或者抽象类来实现;3)具体策略角色:实现了抽象策略角色定义的接口。
三、使用策略模式的程序优化案例让我们看看一家软件公司是如何通过策略模式,改进自己的游戏设计的。
这个游戏先前推出过一款非常成功的小鸭池塘游戏——SimUDuck,里面有各种各样的鸭子,它们在池塘里欢快地游来游去,还会嘎嘎叫。
游戏虽然简单,但可玩性高,因此很受欢迎。
该游戏最初是用标准的OO方式进行设计实现的:有一个超类Duck,而各种具体类型的鸭子都继承该类。
请看设计类图:但现在情况有所变化,公司面临的竞争越来越激烈,许多类似的产品已在市场上出现。
经过一个星期的头脑风暴过程以后,公司高层决定对游戏进行重大变革,至少要在即将召开的董事会上给股东们留下深刻的印象。
公司总裁已经想好了,新游戏的创意要点在于使PC显示屏上的小鸭子能够飞起来,小鸭翅膀扇起的风暴将把竞争对手的类似的模拟游戏吹得远远的。
设计师Joe觉得这也没什么困难的,毕竟这还是一个OO软件,完全可以再次展示自己的OO设计天赋,于是下列设计就产生了:但到了董事会那天,出大事了;现场演示的时候一种特殊的“鸭子”——橡皮鸭子(Rubber Duck)也在屏幕上飞来飞去,笑得股东们前仰后合,但笑完之后就是严厉地指责:我们开发的到底是款什么游戏?公司是不是想改名叫怪物公司()了?面对这个问题,Joe不得不低下高贵的头,承认这个设计有个小缺陷,自己忘了不是所有的Duck的子类都能飞;而fly( )方法放在超类Duck中,结果所有的子类都获得了该方法。
其实Joe的设计背后有明确的目标,即通过继承实现功能的复用,但这种做法却为设计的维护提出了难题。
Joe马上改正错误的设计,并且为了不再犯错误,他对许多问题开始未雨绸寥了。
首先,他使RubberDuck类重载了fly( )方法,这样橡皮鸭子就不会飞了,但仍然会嘎嘎叫。
还有一种特殊的“鸭子”——猎人打猎用的诱饵鸭子,因此这种“鸭子”既不会飞,也不能叫(它一张嘴可就露馅了,野鸭子立刻会明白这不是我兄弟),于是超类Duck中的Quack( )方法也必须被重载,这两个类的类图如下:Joe已经意识到了一个问题:这样的层次架构不能对付各种可能出现的设计变化。
Joe拿到手的备忘录上提到过,总裁们决定每六个月就将产品升级一次(尽管升级的方式他们还没想好)。
Joe知道在这个小鸭游戏中,鸭子的种类会不断变化,其fly( )和quack( )方法会不断变化,这将迫使Joe不得不多次重载这两个方法,而且该过程将永远保持下去……,这种感觉让Joe觉得很不爽。
于是他决定使用接口(interface)这种高级特征改进相关类的层次架构:这个层次架构看起来很不错,使用了继承、接口(自然就有多态性)等OO设计方法,许多国内讲解OO程序设计的书籍的认识深度也不过如此了。
但这样就真的是好的设计了吗?事实上,这个设计堪称愚蠢到了极点。
尽管看起来避免了fly( )和quack( )等少数方法的重载,但却导致了灾难性的“代码重复”问题。
试想,如果有100种小鸭子,由于它们都需要具体实现fly( )、quack( )等方法,那么由于其中90多种小鸭子的fly( )方法代码都相同,或大致相同,那么就需要把这些大同小异的代码在子类中复制90多遍,程序员面对这种编程效果,真是情何以堪!万一以后发现需要对相关方法做修改,哪怕是最小的修改,怎么办?其实,这时代码修改越少,越显得这个设计愚蠢:假设修改内容就是增加一句类似“Hello, world!”,尽管这种修改本身没有任何难度,但你却必须把类似的语句复制90多遍。
何其愚蠢!经典的基于类继承的OO设计方式没有为我们解决问题。
现在OO方法已被人们使用多年,在这个过程人们有了许多心得,并将其总结为各种设计原则,针对我们当前的问题,需要使用这样的设计原则:确定应用程序的不变部分和改变部分,并将它们分开。
该原则还可以这样描述:将变化的部分提出并封装起来,以便在将来对其进行修改和扩展,而不会影响其它不变的部分。
针对我们的问题,现在已知fly( )、quack( )是Duck类的变化部分,它们在不同子类中会不同。
为了将这些方法与Duck类相分离,我们将它们从Duck类拿出,并生成代表这些行为的新类。
如何设计Duck的行为呢?首先,我们必须使得相关设计拥有足够的灵活性;之前的麻烦都是因为对Duck的行为设计缺乏灵活性而引起的。
而现在,我们知道需要为Duck 的实例分配行为,这样才够灵活!想一想,如果我们能产生一个MallardDuck类的实例,并指定其飞行行为的话,为什么不想想办法,使得我们能够动态地改变这只鸭子的行为呢?换而言之,我们希望在运行时改变这只MallardDuck的飞行能力。
请想想,在游戏中这种做法的实际意义?这里,我们再介绍一个设计原则:面向接口编程,而非面向实现编程(Program to an interface, not an implementation)。
该原则可以保证设计的灵活性,我们将慢慢体验到这一点。
首先我们定义两个接口,根据我们的痛苦经验,超类Duck及其子类都不应该实现上述接口。
因为这将导致我们依赖并被锁定在某种具体实现上,这时我们是无法改变其行为的(除非重写代码)。
因此,我们需要定义一系列行为类来表示具体的飞行行为或嘎嘎叫行为。
并将它们通过组合方式加入超类Duck,这样所有子类都会拥有相关的行为定义,并有机会根据自身情况来定义或改变相关行为。
public class FlyWithWings implements FlyBehavior {和Quack.java Squeak.java MuteQuack.java现在,看看上述行为是如何被集成到Duck类中的:Duck类将它的飞行行为和嘎嘎叫行为委托(delegate)给实现了相关接口的行为类,而不再使用自身(或子类)中定义的飞行方法或嘎嘎叫方法;事实上,我们可以看到,新的代码中已经取消了这些方法。
现在看看一种具体子类的实现代码,其它小鸭子的实现就可以以此类推了。
现在画出类结构图来表示我们的新设计:该类图中有我们希望的一切:各种小鸭类都继承了类Duck,各种飞行动作类来自FlyBehavior接口并具体实现之,而各种嘎嘎叫动作类来自QuackBehavior接口并具体实现之。
请注意我们对事情的描述有了一些微妙的变化。
我们不再把鸭子的行为看作是一系列行为,而是把它们当作一族算法。
请你这样想:在这个SimUDuck设计中,算法代表了鸭子会做的事情(不同的嘎嘎叫方式和飞行方式),而我们还可以用同样的技巧在一系列类中实现相关的算法,对不同的州进行不同的销售税计算。
“HAS-A”比“IS-A”更好在这个类图中,体现了一个新的OO设计原则:“优先使用组合,而非类继承(Favor composition over inheritance)”。
我们可以看出,具体的行为类对象通过组合方式被集成到Duck类中。
使用组合来实现功能扩展可使系统拥有更大的灵活性。
你不但可以封装一族算法到相关类中,而且你可以在运行时改变系统行为,只要与正确实现了相关行为接口的对象进行新组合即可。
组合方式被许多设计模式所使用,并且其作用方式得到了越来越多的肯定。
导师:Grasshopper,告诉我你从面向对象方法中学到了什么。
学生:导师,我知道了面向对象方法的承诺是重用。
导师:Grasshopper,请继续……学生:导师,通过继承所有的好东西都可以重用,因此我们可以砍掉大量的开发时间就象我们在树林中飞快地砍竹子一样。
导师:Grasshopper,请问我们花费在代码上的时间更多是在开发结束之前还是之后?学生:答案是“之后”,导师。
我们通常花费更多的时间在维护和修改软件上,而不是最初的开发上。
导师:所以Grasshopper,花在重用的精力应该比花在可维护性和扩展性的精力更多吗?学生:导师,我想应该是这样的。
导师:我看你还有很多东西要学。
我希望你进一步思考有关继承的问题。
正如你已看见的,继承有它的问题,而我们还有其它方法实现重用。
共享模式词汇的威力1.共享模式词汇是强有力的。
当你与其他开发者或你的团队成员使用模式交流时,你不仅在交流时使用了模式名称,而且使用了该模式代表的品质、特征和约束进行交流。
2.模式让你少说废话。
当你在描述中使用模式时,其他开发者能很快地准确知道你脑中的设计。
3.在模式的层次上交谈使得你更久地停留在“设计”中。
用模式讨论软件系统使你们的讨论保持在设计层次上,避免讨论陷入类和对象的实现细节中。
4.共享词汇能够为你的开发团队进行涡轮增压。
一个精通模式的团队能前进得更快,而之间的误会更少。
5.共享词汇鼓励更多初级开发者加速学习。
初级开发者很仰慕那些有经验的开发者。
当资深开发者使用设计模式时,初级开发者也受到鼓舞并开始学习设计模式。
请在你的团队中建立模式使用者社团。
我应该怎样使用设计模式?我们都用过现成的类库和框架。
我们把它们拿过来,按照其API写一些代码,然后把它编译到我们的程序中,就能从别人写的这些代码中获益匪浅。
想想Java API以及它们为你提供的所有功能:网络、GUI、IO,等等。
库和框架向开发模型迈出了一大步,我们只需要挑选出组件并将它们正确地插入即可。