【设计模式 - 22】之策略模式(Strategy)
来源:互联网 发布:ubuntu wine qq2016 编辑:程序博客网 时间:2024/05/01 15:03
1 模式简介
在策略模式中,一个类的行为或其算法可以在运行时改变。策略模式定义了一系列算法,把它们一个个封装起来,并且使它们可以互相替换。
策略模式的优点:
1) 算法可以自由切换;
2) 避免使用多重条件判断;
3) 扩展性良好。
策略模式的缺点:
1) 算法可以自由切换;
2) 避免使用多重条件判断;
3) 扩展性良好。
策略模式的适用场景:
1) 当一个系统中有许多类,它们之间的区别仅在于它们的行为,希望动态地让一个对象在许多行为中选择一种行为时;
2) 当一个系统需要动态地在几种算法中选择一种时;
3) 当一个对象有很多的行为,不想使用多重的条件选择语句来选择使用哪个行为时。
2 案例
在这个例子中,我们来模拟一个游戏:这个游戏中有各种鸭子,它们会飞,也会叫,但它们飞和叫的方式不同,如红头鸭是呱呱叫的,而橡皮鸭是吱吱叫的;红头鸭是用翅膀飞的,而橡皮鸭是不会飞的。我们希望用JAVA编程语言结合策略模式来完成这个功能。
2.1 使用继承
这样做看似没有错误,但实际上存在以下两个方面的错误:
1、子类的可用行为可能远大于我们的期待范围。把所有方法和属性都定义在Duck父类中,再由所有子类去继承这个父类,那么所有的子类就都具备父类的方法和属性。就拿这个游戏的例子来说,如果加入一个方法fly(),那么就算是橡皮鸭(RubberDuck)类也一定会具备fly()的行为。
2、这种方法并不能有效的解决代码重复问题。拿上一条中的fly()方法来说,既然不同的鸭子具有不同的飞行方式,则fly()方法的方法体一定是写在子类中;而不同种类的鸭子的飞行方式也可能是相同的,所以我们就可能不得不在多个鸭子中使用相同的fly()方法,而在另外一些鸭子中使用另一种fly()方法。
2.2 增加接口
我们可以把Duck父类中的fly()方法提取出来定义成接口,称为Flyable,其中定义一个抽象方法fly(),让可以飞的Duck子类实现这个接口并实现fly()方法。各个类中的行为细节及类间关系如下图所示。
使用接口有效的解决了上面的第一个问题,即可以有效的控制各个子类的行为范围,不会出现“子类具有父类的所有方法”的情况了。但是,JAVA中的接口中不具备代码实现功能,所以这样做并没有解决代码重复的问题。
2.3 解决问题
我们需要找出应用中可能需要变化的地方,把它们独立出来,不要和那些不需要变化的代码混在一起,即把会变化的部分取出并封装起来,一边以后可以轻易的改动或扩展此部分,而不影响不需要变化的部分。
在上面的两次尝试(使用继承、增加接口)中,我们都只是把共有的属性和行为抽出来封装成父类或接口,但在这里,我们要尽量两次封装,即在业务类上面还有两层封装类。对于一种行为,我们首先将这种行为抽取出来作为一个总的行为接口,然后再在这个接口下面定义多个不同的实现类,最后再在业务类中调用父类完成业务。简单的说,在上面两种尝试中,我们只是定义了两个互不相关的行为,而在这种方法中,我们定义的是一组有关联的行为。
拿我们这个例子中的fly()方法举例,飞,可能是用翅膀飞(FlyWithWings),也可能是坐火箭飞(FlyRocketPower)。因此,我们定义一个总的接口FlyBehavior,在这个接口中定义一个抽象方法fly()。再定义两个实现FlyBehavior接口的类FlyWithWings和FlyRocketPower,这两个类实现FlyBehavior接口,并实现接口中的fly()方法。另外,我们在Duck父类中定义一个FlyBehavior的接口变量,在生成鸭子实体的时候,给其FlyBehavior赋值,以此决定鸭子的飞行方式。我们还可以在Duck父类中定义一个设置飞行方式的方法setFlyBehavior(),来动态的改变鸭子的飞行方式。以下是类图:
以下贴出对这个问题的解决方案的代码:
飞行接口FlyBehavior中的代码:public interface FlyBehavior {// 飞行的抽象方法void fly();}使用翅膀飞行类FlyWithWings中的代码:
public class FlyWithWings implements FlyBehavior {@Overridepublic void fly() {System.out.println("使用翅膀飞行");}}
public interface QuackBehaviro {// 叫的抽象方法void quack();}呱呱叫的类Quack中的代码:
public class Quack implements QuackBehaviro {@Overridepublic void quack() {System.out.println("呱呱叫");}}其实还有吱吱叫的类Squeak,这里就不贴出来了。
public class Duck {protected FlyBehavior flyBehavior;protected QuackBehaviro quackBehaviro;public void performFly() {flyBehavior.fly();}public void performQuack() {quackBehaviro.quack();}public void setFlyBehavior(FlyBehavior flyBehavior) {this.flyBehavior = flyBehavior;}public void setQuackBehaviro(QuackBehaviro quackBehaviro) {this.quackBehaviro = quackBehaviro;}}鸭子的一个子类红头鸭RedHeadDuck中的代码:
public class RedHeadDuck extends Duck {public RedHeadDuck() {System.out.println("只是一只红头鸭");super.flyBehavior = new FlyWithWings();super.quackBehaviro = new Quack();}}鸭子的另一个子类橡皮呀RubberDuck中的代码:
public class RubberDuck extends Duck {public RubberDuck() {System.out.println("这是一只橡皮鸭");super.flyBehavior = new FlyNoWay();super.quackBehaviro = new Squeak();}}测试类Test中的代码:
public class Test {public static void main(String[] args) {Duck redHeadDuck = new RedHeadDuck();redHeadDuck.performFly();redHeadDuck.performQuack();System.out.println();Duck rubberDuck = new RubberDuck();rubberDuck.performFly();rubberDuck.performQuack();}}运行结果如下图所示:
下面贴出策略模式代码的GitHub地址:【GitHub - Strategy】。
- 【设计模式】之策略模式(Strategy)
- 设计模式之--策略模式(Strategy)
- 设计模式之策略(strategy)模式
- 设计模式之策略模式(Strategy)
- 设计模式之策略模式(Strategy)
- 设计模式之:策略模式(strategy)
- 设计模式之策略(Strategy)模式
- 设计模式之策略模式(strategy)
- 设计模式之策略模式(STRATEGY)
- 【设计模式 - 22】之策略模式(Strategy)
- 设计模式之Strategy(策略)
- 设计模式之Strategy(策略)
- 设计模式之Strategy(策略)
- 设计模式之Strategy(策略)
- 设计模式之Strategy(策略)
- 设计模式之Strategy(策略)
- 设计模式之Strategy(策略)
- 设计模式之Strategy(策略)
- Hadoop中基于文件的数据格式(1)SequenceFile
- 2016年第六届ACM趣味编程循环赛 Round #1 B题
- Spring AOP 配置文件的简单理解
- 编译MeshLab(3)—VS2010编译MeshLab源码之编译meshlab_mini.pro
- JavaWeb ( HttpServletRequest,HttpServletResponse)
- 【设计模式 - 22】之策略模式(Strategy)
- JAVA 中 List Set 总结
- 汇编语言笔记整理(三)
- Android 文字和按钮Button点击效果的(selector使用)直接用
- Disruptor原理与编程实践
- 我是怎样在美团点评做App需求迭代的
- Java做的文本编辑器
- 容器执行Servlet API (ServletContext、ServletContextListener、Filter、Servlet的执行顺序)
- 信号的基本概念