对于代码中总是会有需要变化的部分和需要固定不变的部分。对于需要变化的部分,一般可以采用继承的方式,让子类对父类的方法进行重写,以改变已有的行为;如果变化的部分并不是所有子类都必须要有的,那就可以采用接口的形式,含有该行为的子类实现该接口,不含该行为的子类就不用实现,这样就可以保证子类的按序扩展。

这种继承父类和实现接口的方式在大多数情况下是比较有效的,但是当情况比较复杂的时候,比如子类并不需要父类的所有方法,那么继承就造成代码在子类中重复而且子类中含有不合时宜的方法。如果使用接口,子类按需实现接口,如果子类继承接口,子类中需要覆写的代码有时就会很多且重复甚至是没必要但也不得不遵守java语法规则去一个一个的覆写这些方法,而且当需要修改接口的时候,就需要将所有实现该接口的类也进行修改。

在继承父类和实现接口都显得很无力的时候,就可以考虑采用策略模式将需要改变的部分单独独立出来,每一种需要改变的部分实现为一组类,不要将其与不变的代码混在一起。

策略模式定义及组成

策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。

策略模式的组成:

  1. 抽象策略角色: 策略类,通常由一个接口或者抽象类实现。
  2. 具体策略角色:包装了相关的算法和行为。
  3. 环境角色:持有一个策略类的引用,最终给客户端调用。

策略模式类图

上图定义了一个鸭子父类Duck,两个接口flyBehaviour和quackBehaviour。其中的Duck及其子类相当于环境角色,给客户端调用,显示鸭子的一系列行为;两个接口分别相当于是抽象策略角色;两个接口的子类实现相当于具体策略角色,实现了抽象策略角色的方法并包装了各自的独特的行为。

此外上述的类图也体现了一个编程原则针对接口编程而不是针对具体实现编程,这样Duck类的行为就不会被具体实现给固定,便于扩展。

策略模式实际上使用了多个类的组合来实现系统的弹性,不仅将算法封装成了类而且还实现了在运行时动态的改变类的行为。这也符合多用组合少用继承的面向对象设计原则

适用场景

对于一个类中既含有变化部分又含有不变的部分,而且变化部分需要随时间变化而不断的扩展的时候可以考虑使用策略模式。对于简单的代码使用继承和接口也是可以很好的完成相应的效果,但是对于比较复杂且需要不断扩展的系统,策略模式就可以提现价值了。

比如在一个系统中,所有对系统的操作都要有日志记录,而且这个日志还需要有管理界面,这种情况下通常会把日志记录在数据库里面,方便后续的管理,但是在记录日志到数据库的时候,可能会发生错误,比如暂时连不上数据库了,那就先记录在文件里面,然后在合适的时候把文件中的记录再转录到数据库中。对于这样的功能的设计,就可以采用策略模式,把日志记录到数据库和日志记录到文件当作两种记录日志的策略,然后在运行期间根据需要进行动态的切换。

http://chjavach.iteye.com/blog/698743

java示例代码

环境角色,鸭子父类

flyBehavior属性和quackBehavior属性以及这两个属性对应的set方法保证了可以在运行的时候动态的修改角色的行为。

public abstract class Duck {FlyBehavior flyBehavior;QuackBehavior quackBehavior;public Duck() {}public void setFlyBehavior(FlyBehavior fb) {flyBehavior = fb;}public void setQuackBehavior(QuackBehavior qb) {quackBehavior = qb;}public abstract void display();public void performFly() {flyBehavior.fly();}public void performQuack() {quackBehavior.quack();}public void swim() {System.out.println("All ducks float, even decoys!");}}

继承于该父类的环境角色–不同的鸭子类

public class MallardDuck extends Duck {public MallardDuck() {quackBehavior = new Quack();flyBehavior = new FlyWithWings();}public void display() {System.out.println("I'm a real Mallard duck");}}
public class RubberDuck extends Duck {public RubberDuck() {flyBehavior = new FlyNoWay();quackBehavior = new Squeak();}public void display() {System.out.println("I'm a rubber duckie");}}

抽象策略角色–可变部分的接口

鸣叫的接口

public interface QuackBehavior {public void quack();}

飞行的接口

public interface FlyBehavior {public void fly();}

具体策略角色–实现抽象策略角色的类

public class FlyWithWings implements FlyBehavior {public void fly() {System.out.println("I'm flying!!");}}public class FlyNoWay implements FlyBehavior {public void fly() {System.out.println("I can't fly");}}
public class Quack implements QuackBehavior {public void quack() {System.out.println("Quack");}}public class Squeak implements QuackBehavior {public void quack() {System.out.println("Squeak");}}

测试代码

public class StrategyTest extends TestCase {@Testpublic void testDuck(){Duck mallard = new MallardDuck();mallard.display();mallard.performFly();mallard.performQuack();System.out.println("--------------------------------------------------------");Duck rubberDuck = new RubberDuck();rubberDuck.display();rubberDuck.performFly();rubberDuck.performQuack();System.out.println("--------------------------------------------------------");Duck model = new ModelDuck();model.display();model.performFly();model.performQuack();model.setFlyBehavior(new FlyRocketPowered());model.performFly();System.out.println("--------------------------------------------------------");}}

测试结果

策略模式总结

优点:

  1. 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码转移到父类里面,从而避免重复的代码。

  2. 策略模式提供了可以替换继承关系的办法。继承可以处理多种算法或行为。如果不是用策略模式,那么使用算法或行为的环境类就可能会有一些子类,每一个子类提供一个不同的算法或行为。但是,这样一来算法或行为的使用者就和算法或行为本身混在一起。决定使用哪一种算法或采取哪一种行为的逻辑就和算法或行为的逻辑混合在一起,从而不可能再独立演化。继承使得动态改变算法或行为变得不可能。

  3. 使用策略模式可以避免使用多重条件转移语句。多重转移语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重转移语句里面,比使用继承的办法还要原始和落后。

缺点:

  1. 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。

  2. 策略模式造成很多的策略类,每个具体策略类都会产生一个新类。有时候可以通过把依赖于环境的状态保存到客户端里面,而将策略类设计成可共享的,这样策略类实例可以被不同客户端使用。换言之,可以使用享元模式来减少对象的数量。

【设计模式】java设计模式之 -- 策略模式相关推荐

  1. 设计模式 by Python1:策略模式

    设计模式 by Python1:策略模式 最近开始重新看<Head First 设计模式>,作为一个不错的练习,打算在整理设计模式笔记的时候用Python实现. 作为第一个介绍的设计模式, ...

  2. 设计模式解读之一: 策略模式——鸭子游戏

    设计模式解读之一: 策略模式--鸭子游戏 当我们掌握了Java的语法,当我们了解了面向对象的封装.继承.多态等特性,当我们可以用Swing.Servlet.JSP技术构建桌面以及Web应用,不意味着我 ...

  3. 设计模式初学者系列-策略模式 -------为什么总是继承

    设计模式初学者系列-策略模式                                                 -------为什么总是继承 模板方法的延续 这篇稿子是基于我的前一篇模板 ...

  4. 老王讲设计模式(一)——策略模式

    策略模式属于对象的行为模式.其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换.策略模式使得算法可以在不影响到客户端的情况下发生变化. 老王最近接到一个工作,上 ...

  5. 设计模式(三)策略模式——在Spring中使用策略模式

    前言 在 设计模式(一)策略模式 -- 策略模式结构 和 设计模式(二)策略模式 -- 在程序中通过枚举使用策略模式 两篇博文中分析了策略模式的基础使用,在实际的项目开发中要结合spring容器使用策 ...

  6. C++设计模式学习笔记:策略模式

    C++设计模式学习笔记:策略模式 策略模式设计商场促销 1.策略模式介绍 2.商场收银系统策略模式实现 3.策略模式与工厂模式结合 3.策略模式与工厂模式对比 策略模式设计商场促销 1.策略模式介绍 ...

  7. java 模板方法_设计模式(java实现)_模板方法模式(Template method)

    设计模式(java实现)_模板方法模式(Template method) 模板方法模式是编程中经常用到到的模式.它定义了一个操作中的算法骨架,将某些步骤延迟到子类中实现.这样,新的子类可以在不改变一个 ...

  8. 从java多态到策略模式_设计模式中的多态——策略模式详解

    2. 策略模式详解 2.1 策略模式定义 策略模式定义了一系列算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式让算法独立于使用它的客户端而独立的变化. 可以使用多态进行类比来理解策略模 ...

  9. java设计模式实战-(反射+策略模式)

    学完23种设计模式,相信很多同学都疑问,除了单例模式.工厂模式其他模式还有运用的场景吗? 现在这里就举一个例子. 首先策略模式需要先有了解,我们常用策略模式解决实际开发中的if else特别多的场景. ...

  10. Java设计模式之3种策略模式实现

    一.什么是策略模式   所谓策略模式,就是定义了一组策略,分别封装在不同类中,每种策略都可以根据当前场景相互替换,从而使策略的变化可以独立于操作者.比如我们要去某个地方,会根据距离的不同来选择不同的出 ...

最新文章

  1. 闭关纪要17.Google app engine的简单应用
  2. 各种排序算法的JAVA实现
  3. python上海培训哪里比较好-上海十大python培训机构排名
  4. 【Android开发日记】第一个任务Android Service!Service靴+重力感应器+弹出窗口+保持执行...
  5. 抽象工厂模式解析例子
  6. 稳压电源的设计与制作_电子爱好设计的直流可调压电源电路,太完美了,有图,亲测可用...
  7. delphi常用函数大全(转)
  8. 几万字的博文,你自己会看吗
  9. html鼠标悬停边框颜色,鼠标悬浮在输入框改变边框颜色或背景色代码
  10. c1083无法打开 mysql_fatal error C1083: 无法打开包括文件:stdbool.h: No such file or directory...
  11. Java实现特征保持的图像加密算法
  12. 别人口中的“蓉叶云库”
  13. cmake出错:Building inplace are not allowed. You should create a separate directory for Building.
  14. 2008年的各国卫星导航系统比较(北斗、伽利略、GLONASS、GPS)
  15. 如何防止亚马逊账号关联的一些建议值得卖家们收藏?
  16. 到底是上班舒服还是上学舒服!上班一个月的感受!
  17. 如何使用10个小时搭建出个人域名而又Geek的独立博客?
  18. 计算机表格怎么同时选中分开的两项,excel怎么把三个单元格分成两个
  19. 日本美术学校有哪些,日本美术学校排名榜
  20. 人手必备,策略中最常用的5类Python数据接口

热门文章

  1. java 2d划线 刷子_Java图形设计中,利用Bresenham算法实现直线线型,线宽的控制(NO2DGRAPHICS)...
  2. 托管代码与非托管代码
  3. adb安装apk是出现INSTALL_FAILED_INSUFFICIENT_STORAGE
  4. iOS10 推送通知 UserNotifications
  5. 《JavaScript面向对象精要》——1.8 原始封装类型
  6. 第19课:Spark高级排序彻底解密
  7. 如何使用ember下拉框组件??
  8. CentOS 6 同一台机器部署多个Tomcat应用服务器
  9. C#中获取当前应用程序的路径及环境变量
  10. 风暴数码论坛教程--apk和odex的介绍和合并