strategy 策略模式

上传人:豆浆 文档编号:24902928 上传时间:2017-12-08 格式:PDF 页数:36 大小:553.45KB
返回 下载 相关 举报
strategy 策略模式_第1页
第1页 / 共36页
strategy 策略模式_第2页
第2页 / 共36页
strategy 策略模式_第3页
第3页 / 共36页
strategy 策略模式_第4页
第4页 / 共36页
strategy 策略模式_第5页
第5页 / 共36页
点击查看更多>>
资源描述

《strategy 策略模式》由会员分享,可在线阅读,更多相关《strategy 策略模式(36页珍藏版)》请在金锄头文库上搜索。

1、1Design Pattern设计模式课程1:Strategy Pattern 2关于模式模式模式描述了一个在我们的环境中不断出现的问题,然后描述了该问题的解决方案的核心。通过这种方式,你可以无数次地使用那些已有的解决方案,无需在重复相同的工作。-建筑的永恒之道Alexander 模式其实就是解决某一类问题的方法论。把解决某类问题的方法总结归纳到理论高度,那就是模式。模式对问题的描述以及对问题的解答应具有高度的抽象性和代表性。模式是对现实生活某类现象的共同特质的高度抽象,描述了事务或者现象的规律,这种规律以及解决方法对于类似的现象同样有用。3设计模式软件的设计模式指在软件设计和开发过程中,不断

2、总结出来的,反应了某一类设计问题的解决方案。模式是一种指导,在一个良好的指导下,有助于你完成任务,有助于你作出一个优良的设计方案,达到事半功倍的效果。而且会得到解决问题的最佳办法。设计模式使人们可以更加简单方便地复用成功的设计和体系结构。4为什么我们要使用设计模式?设计模式帮助你从别人的成功经验而不是你自己的失败那里学到更多东西;- Mark Johnson设计模式提供了一种共享经验的方式,可以使团体受益和避免不断的重复发明。5一些设计原则1面向接口编程的原则面向接口编程,而不是面向实现编程。可变性封装的原则在设计时应当考虑系统中什么可能会发生变化,或者什么特性具备多变的特征。这种变化不应该散

3、落在代码中的各个角落,而是应该被适当的封装起来,以便于维护以及扩展;开闭原则软件中的实体(包括类,模块,函数等等)应当是可扩展的(开),而不应被修改(闭)。里氏替换原则 子类可以扩展父类的功能,但不能改变父类原有的功能。 所有引用基类的地方必须能透明地使用其子类的对象.依赖倒转原则高层模块不应该依赖于低层模块。二者都应该依赖于抽象。抽象不应该依赖于细节。细节应该依赖于抽象。6一些设计原则2组合/聚合复用原则尽量使用组合/聚合、尽量不使用继承在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新的对象通过向这些对象的委派达到复用这些对象的目的接口隔离原则避免接口污染;恰当的划分角色和接

4、口;从一个客户类的角度来讲:一个类对另外一个类的依赖性应当是建立在最小的接口上的使用多个专门的接口比使用单一的总接口要好所有设计原则的目标都是为了使软件:降低耦合,增强灵活性。在接下来的设计模式的讲解中,我们再来体验这些设计原则给我们带来的方便7从一个例子开始:DuckSimulator这是一个鸭池仿真游戏仿真鸭。这个游戏可以展现了所有种类鸭子的游泳和嘎嘎叫声。最初的系统设计者使用了标准的面向对象的技术并创建了“鸭”基类,使得其他种类的鸭可以继承。Duckquack( )swim ( )display ( )/ Other duck like methodsMallardDuckdisplay

5、 ( ) / looks like a mallard RedHeadDuckdisplay ( ) / looks like a mallard 所有的鸭子都会嘎嘎叫和游泳,这个基类提供了这些实现的代码大多数类型的鸭子都从这个Duck类中继承每一类鸭子负责实现自己的展现行为,使之可以在显示器上展现出来Display()方法是抽象的,因为不同类型的鸭子看起来是不一样的8客户要求为鸭子增加“飞”的功能Duckquack( )swim ( )display ( )/ Other duck like methodsFly( ):viodMallardDuckdisplay ( ) / looks l

6、ike a mallard RedHeadDuckdisplay ( ) / looks like a mallard 我仅仅只需要在Duck类里增加fly()方法,然后所有其他鸭子就都可以继承它了。Joe正好接手这个项目开始展开工作,他想:现在是展示我真正的面向对象才华的时候了。嘿嘿所有的子类都从Duck基类中继承了fly()方法。Joe在基类Duck中增加了一个方法,以为大功告成9但似乎发生了很严重的错误Duckquack( )swim ( )display ( )/ Other duck like methodsFly( ):viodMallardDuckdisplay ( ) / lo

7、oks like a mallardRedHeadDuckdisplay ( ) / looks like a mallardRubberDucksqueak()display ( ) / looks like a mallardJoe,我正在股东大会上。他们刚看完演示,很多橡皮鸭子在屏幕上四处乱飞。给Duck基类增加新行为的时候,他也同时给那些不需要这些行为的Duck的子类增加了。橡皮鸭子不会嘎嘎叫,所以quack()被覆盖为了Squeak(尖叫)好吧,我的设计有一点小缺陷。我不明白为什么他们不能只部分调用它。10继承带来的一系列问题DecoyDuckQuack()/ Override to

8、 do nothingdisplay ( ) / looks like a mallardFly()/Override to do nothingRubberDucksqueak()display ( ) / looks like a rubberDuckFly()/Override to do nothing我可以总是在橡皮鸭子里覆盖fly()方法,同样的方式对于quack()方法但是当我们在系统里增加木头鸭子的时候会怎么样呢?它们既不会飞也不会呷呷叫这里有另外一个类,注意这个类与橡皮鸭类似,它不会飞,但也不会嘎嘎叫11简单的测试测试一下下面那些是使用继承来给Duck增加行为的不利条件?(可

9、多选) A. 代码在子类间被复制B. 很难在运行时改变行为C. 我们不能让鸭子跳舞D. 很难得到所有鸭子的行为E. 鸭子不能在同一时间飞和呷呷叫F. 变动会无意间影响其他鸭子12利用接口(interface)如何?你觉得这个设计怎么样?J o e 认识到继承可能不是一个好的解决方法,因为他刚刚拿到来自主管的备忘录,希望以后每六个月更新产品(至于更新的方法,他们还没想到)。J o e 知道规格会常常改变,每当有新的鸭子子类出现,他就要被迫检视并可能需要覆盖fly() 和quark(). 这简直是无穷尽的恶梦。我可以把fly()从Duck()基类中抽取出来,然后创建一个有fly()方法的Flyab

10、le()接口。这样,只有那些需要飞的鸭子才会通过实现这个接口来获得fly()方法并且,我想最好再创建一个Quackable接口,因为并不是所有的鸭子都会呷呷叫。13用接口实现就没问题了吗?等等,如你所说,是不是意味着重复的代码?这真是一个超笨的主!如果你能想到被迫覆盖一些方法是不好的,那么你为什么不考虑一下当你需要对飞行行为做一点小的改动的时候会怎么样对于所有48个能够飞行的Duck的子类来说?!有没有一种理想的方法,使我们可以用一种对现有代码影响最少的方式来修改软件呢?那样我们就可以花很少的时间来修改软件而有更多的时间给程序增加更酷的功能14我们似乎忘了些什么东西在软件开发中你必须一直关注的

11、事情是什么?什么样的情况可能带来软件功能的变化呢?我的客户或者用户决定还需要某些东西或者他们需要一个新的功能。公司决定与另外一个数据库提供商合作,并且他的数据是从另外一个供应商那里购买的具有不同格式的数据15我们极力期望的是:当问题发生时,改动最小,如果能做到零调整我们知道使用继承并不能很好的解决问题,因为鸭子的行为在子类里持续不断地改变,并且让所有的子类都拥有基类的行为是不适当的。Flyable和Quackable接口开始听起来挺有希望的只有那些真正会飞的鸭子才会实现Flyable接口,等等但是Java的接口里不具有实现代码,所以就没有代码重用。那意味着不论何时你需要修改一个行为,你就被迫要

12、在所有定义了这个行为的不同子类里循环修改它,这种方法可能会引入新的错误!很幸运,正好有一个设计原则(Design Principle)适合来处理这种情形。Identify the aspects of yourapplication that vary and separatethem from what stays the same.识别在程序中的那些多变的特征,并且把它们和稳定的特征分离开来把那些变化比较快的特征封装起来,使得它不再影响其他代码的稳定性结果呢?代码变更时较少出现无意义的错误,而系统变得更加柔性。这是我们将要涉及到的众多设计原则中的第一个原则。以后还有更多原则会陆续出现。16

13、对于这个原则,还有另外一种解释:抽取那些变化比较快的特征并封装它们,接下来我们就可以改变或者扩展这些特征而不会影响那些没有使用到该特征的程序;尽管说起来比较简单,但它几乎是所有设计模式的基础。所有的模式都提供了一个方法使得那些变化比较快的特征与其他特征独立。OK,我们来从Duck类中抽取鸭子的行为。Identify the aspects of yourapplication that vary and separatethem from what stays the same.识别在程序中的那些多变的特征,并且把它们和稳定的特征分离开来17首先,识别可变的特征Duck仍然是所有鸭子的基类,但

14、是我们把飞和叫的行为抽取出来并放到了其他的类架构中了。Duck Behaviors把变化的特征抽取出来我们知道fly()和quack()是大多数鸭子的具备的特征。从Duck类中分离出这些行为,我们将抽取所有duck类的行为并创建相应的类来负责各自的行为。现在我们来分离出那些变化的特征,我们将从鸭子的基类中分离出两组类,一组是“飞“行为的类,另一组是“叫”行为的类。每一类都能执行它各自的行为。例如,我们可以实现一个实现嘎嘎叫的类,另一个实现尖叫的类,再另一个实现不发声类。现在所有可变的行为实现都从Duck类中剥离出来了18设计原则:面向接口编程,而非面向实现编程我们将怎么样设计那组实现了飞行和呷

15、呷叫行为的类呢?OK,我们再来看一个设计原则Program to interface, not animplementation.面向接口编程,而不是面向实现编程从现在起,鸭子的行为将被封装在被分离的类中,一个类实现一个具体行为接口。通过这个方法,鸭子这个类不需要知道他们任何一个行为的具体实现方法和细节。我们设计了一个FlyBehavior接口,所有需要飞行的类都必须实现它。所有新的飞行类只需要实现这个fly()方法就可以了。19再来讨论一下我不明白你为什么非要使用FlyBehavior接口呢?你可以使用一个抽象类来做同样的事。难道所有的目的不都是为了使用多态吗?“Program to an interface” really means“Program to a supertype.”针对接口编程实质上是针对基类(SuperType)的编程面向实现的编程,代码可能如下:Dog dnew Dog();d.Bark();面向接口和基类的编程,代码可能如下:Animal animalnew Dog () ;animal.makesound();上述实现的子类的实例(new Dog()是硬编码,其实我们可以做得更好,我们可以在运行的时候才指派具体实现的对象:a =getAnimal() ;animal.makesound();声明一个Dog类型的变量“

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 商业/管理/HR > 其它文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号