一、了解策略模式

1.1 什么是策略模式

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

1.2 策略模式组成结构

  • 环境 (Context):持有一个策略类的引用,最终给客户端调用。
  • 抽象策略 (Strategy): 策略类,通常是一个接口或者抽象类。
  • 具体策略 (ConcreteStrategy):实现了策略类中的策略方法,封装相关的算法和行为。

1.3 策略模式 UML 图解

1.4 策略模式应用场景

  • 多个类只区别在表现行为不同,可以使用 Strategy 模式,在运行时动态选择具体要执行的行为。
  • 需要在不同情况下使用不同的策略 (算法),或者策略还可能在未来用其它方式来实现。
  • 对客户隐藏具体策略 (算法) 的实现细节,彼此完全独立。

二、策略模式具体应用

2.1 问题描述

模拟鸭子游戏:游戏中会出现各种鸭子,一边游泳戏水、一边呱呱叫,为了提高游戏的乐趣,加入了让鸭子飞的功能。但是考虑到并不是所有的鸭子都会飞,比如下面这种橡皮鸭。现在让你利用 OO 技术,设计鸭子相关的类。

2.2 使用继承

我们可能想到使用继承,在超类 Duck 中定义鸭子的相关方法,并实现其对应的动作,这样就能让所有鸭子都可以对应其 fly() 的动作。在定义橡皮鸭时,只需要覆盖其父类 (Duck) 中的 fly() 方法即可。

如果我们还想加入诱饵鸭,这种鸭子既不会叫,也不会飞,那么我们就要继承 Duck 类,重写其中的 quack() 、display() 和 fly() 方法。

这种通过继承的方法是可以解决问题,但是有很多的局限

  • 代码在多个子类中重复。
  • 运行时的行为不容易改变。
  • 很难知道鸭子的全部行为。
  • 改变会牵一发动全身,造成其他鸭子不想要的改变。

2.3 使用接口

认识到上面继承的不足,我们可能想到了另一种方式去解决这种问题,通过接口的方式去实现某些动作。把 fly() 和 quack() 方法从 Duck 类中抽取抽取出来,分别放在 Flyable 和 Quackable 接口中。

通过接口的方式是可以完成任务,但是这也确实是一个很笨的方式。因为对于很多种鸭子来说,它们大部分都会飞与呱呱叫,但是我们在定义它们类的时候都要去实现 Flyable 和 Quackable 接口,这样一来重复的代码更多了。

2.4 问题归零

到这里我们知道使用继承并不能很好的解决问题,因为鸭子的行为在子类中是不断变化的,并且让所有的鸭子都具有这些行为是不恰当的,比如橡皮鸭不具有飞的行为。通过接口的方式似乎还不错,但是 Java 接口并不具备实现代码,所以继承接口并不能达到代码复用的目的,一不小心,就可能造成新的错误!

幸运的是,有一个设计原则,恰好适用于这种状况:找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。这样以来,代码变化引起的后果变少,系统将更有弹性。

2.5 策略模式登场

除了 fly() 和 quack() 方法之外,Duck 中的其他方法还算一切正常,没有什么需要经常需要变化或修改的地方。所以除了 fly() 和 quack() 方法,我们不打算对 Duck 中的其他方法做太多处理。我们希望一切具有弹性,正是因为没有弹性,上面两种方法都被我们淘汰掉了。

比如说,我们要产生一个绿头鸭的实例,并制定特定“类型”的飞行行为给它。我们可以在鸭子类中包含设定行为的方法,这样就可以在“运行时”动态地“改变”绿头鸭的飞行行为。

有了这些实现目标,于是就有了第二个设计原则:针对接口编程,而不是针对实现编程。

这里我们使用接口代表每个行为,比如说,FlyBehavior 与 QuackBehavior,而行为的每个实现都将实现其中一个接口。所以这次鸭子类不会去实现 Flyable 和 Quackable 接口,反而是由我们制造一组其他类专门实现 FlyBehavior 与 QuackBehavior,这就称为“行为”类。由行为类而不是 Duck 类来实现该接口。

(1)策略模式设计图

改造原来的鸭子类

(2) 代码实现

这里我们将 Duck 类定义成抽象类,并把 display() 方法定义成抽象方法。

接口 QuackBehavior

package com.jas.strategy;public interface QuackBehavior {void quack();
}

接口 QuackBehavior 实现类 Quack(实现鸭子呱呱叫)

package com.jas.strategy;public class Quack implements QuackBehavior {@Overridepublic void quack() {System.out.println("Quack!");}
}

接口 QuackBehavior 实现类 SQuack(实现鸭子橡皮吱吱叫)

package com.jas.strategy;public class SQuack implements QuackBehavior {@Overridepublic void quack() {System.out.println("SQuack!");}
}

接口 QuackBehavior 实现类 MuteQuack(实现鸭子不会叫)

package com.jas.strategy;public class MuteQuack implements QuackBehavior {@Overridepublic void quack() {System.out.println("Silence!");}
}

接口 FlyBehavior

package com.jas.strategy;public interface FlyBehavior {void fly();
}

接口 FlyBehavior 实现类 FlyWithWings(实现鸭子飞)

package com.jas.strategy;public class FlyWithWings implements FlyBehavior {@Overridepublic void fly() {System.out.println("I'm flying!");}
}

接口 FlyBehavior 实现类 FlyNoWay(实现鸭子不会飞)

package com.jas.strategy;public class FlyNoWay implements FlyBehavior {@Overridepublic void fly() {System.out.println("I can't fly!");}
}

Duck 类

package com.jas.strategy;public abstract class Duck {private QuackBehavior quackBehavior;private FlyBehavior flyBehavior;public void swim(){System.out.println("All ducks float.");}public abstract void display();public void performQuack(){quackBehavior.quack();}public void performFly(){flyBehavior.fly();}public void setQuackBehavior(QuackBehavior quackBehavior){this.quackBehavior = quackBehavior;}public void setFlyBehavior(FlyBehavior flyBehavior){this.flyBehavior = flyBehavior;}}

测试类 RubberDuck

package com.jas.strategy;public class RubberDuck extends Duck {@Overridepublic void display() {System.out.println("Rubber Duck");}public static void main(String[] args) {Duck rubberDuck = new RubberDuck();    //橡皮鸭实例rubberDuck.setQuackBehavior(new SQuack());    //橡皮鸭吱吱叫rubberDuck.setFlyBehavior(new FlyNoWay());    //橡皮鸭不会飞rubberDuck.performQuack();rubberDuck.performFly();}
}//输出
//SQuack!
//I can't fly!

2.6 从策略模式组成结构对问题进行总结

三、策略模式总结

3.1 策略模式的优缺点

优点

1、 策略模式提供了管理相关的算法族的办法,从而避免重复的代码。
2、 策略模式提供了可以替换继承关系的办法。因为继承使得动态改变算法或行为变得不可能。
3、 使用策略模式可以避免使用多重条件转移语句。

缺点

1、客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
2、 策略模式造成很多的策略类,每个具体策略类都会产生一个新类。

PS:点击了解更多设计模式 http://blog.csdn.net/codejas/article/details/79236013

四、参考文献

《Head First 设计模式》

Java 设计模式之策略模式相关推荐

  1. Java设计模式之策略模式与状态模式

    一.策略模式定义 定义:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们之间可以相互替换,策略模式可以在不影响客户端的情况下发生变化. 好了,定义看看就完了,我知道你很烦看定义. 二.策 ...

  2. Java设计模式之策略模式(UML类图分析+代码详解)

    大家好,我是一名在算法之路上不断前进的小小程序猿!体会算法之美,领悟算法的智慧~ 希望各位博友走过路过可以给我点个免费的赞,你们的支持是我不断前进的动力!! 加油吧!未来可期!! 本文将介绍java设 ...

  3. Java设计模式之策略模式+工厂模式+模板模式

    Java设计模式之策略模式+工厂模式+模板模式 1.策略模式+工厂模式+模板模式 个人的理解:实际开发工程中,一些业务很复杂的逻辑使用很多的 if 或者 if···else 语句,不利于维护和扩展,为 ...

  4. 【Java设计模式】策略模式

    (转载请注明出处:http://blog.csdn.net/buptgshengod) 1.背景知识 策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法.比如每 ...

  5. java解决策略膨胀_折腾Java设计模式之策略模式

    简介 在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改.这种类型的设计模式属于行为型模式.简单理解就是一组算法,可以互换,再简单点策略就是封装算法. 意图 定义一 ...

  6. 【设计模式】java设计模式之 -- 策略模式

    对于代码中总是会有需要变化的部分和需要固定不变的部分.对于需要变化的部分,一般可以采用继承的方式,让子类对父类的方法进行重写,以改变已有的行为:如果变化的部分并不是所有子类都必须要有的,那就可以采用接 ...

  7. Java设计模式之策略模式---写的比较有趣,推荐大家看看

    原文:http://blog.csdn.net/jason0539/article/details/45007553 背景 在软件开发中常常遇到这种情况,实现某一个功能有多种算法或者策略,我们可以根据 ...

  8. 《Java设计模式之策略模式》

    <二 >策略模式   相信很多人都玩过魔兽世界这款游戏,它里面的战士有三种姿态:防御.狂暴.战斗,那么在不同的场景下我们需要使用不通的姿态,比如当MT抗怪就需要使用防御姿态,战场需要使用战 ...

  9. Java设计模式之——策略模式

    策略模式的简单介绍 在软件开发中常常遇到这样的情况:实现某一个功能可以有多种算法或者策略,我们根据事件情况选择不同的算法或者策略来完成该功能.例如,排序算法,可以使用插入排序.归并排序.冒泡排序等. ...

最新文章

  1. 推荐一位二本毕业1年,上海买房的大佬,牛逼!
  2. 一个量子物理学家是怎样研究 AI 的? | 8月书讯
  3. [云炬python3玩转机器学习笔记] 3-12 数据加载和简单的数据探索
  4. Idea缺少Version Control 底部菜单
  5. CM: How is attachment version implemented
  6. Nginx动静分离实现负载均衡
  7. mysql force Index 强制索引[转]
  8. hdu1002——A + B Problem II
  9. 苹果mac休眠快捷键_新手小白用苹果电脑搞科研,学会这些才不至于尴尬!
  10. Beyond Compare比较class文件
  11. (转载)基于联盟链区块链的九个方面对比
  12. 爱荷华州立 计算机博士,2020年美国爱荷华州立大学博士全奖招生
  13. 参加计算机比赛英语,高中英语作文关于电脑比赛的
  14. 计算机的宽带用户名没有了怎么办,电脑没办法建立宽带连接怎么办
  15. centos上安装cdh2.6的方法
  16. 等比序列的实际应用 —等额本息还款金额公式推导
  17. 企业微信与微信相比的好处有有哪些?
  18. 网吧运行linux,开Linux网吧行不行得通?
  19. python是一种代表简单主义思想的语言_python区别于其他语言的优势是什么
  20. mysql积累——长期更新

热门文章

  1. IDEA出现Error during artifact deployment. See server log for details.
  2. mysql批量更新,批量插入之replace语句/insert into... on duplicate key update语句
  3. nginx配置ajax请求跨域
  4. vue实现表格组件,带分页
  5. HTTPS和HTTPS证书
  6. Java实现复制文件
  7. springboot集成测试时@RunWith和@SpringBootTest爆红不能测试
  8. 2019牛客暑期多校训练营(第九场)
  9. Applese 的毒气炸弹
  10. 【实例记录】在ubuntu上运行python实现与单片机多线程串口通信