策略模式

策略模式

定义

定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。

问题描述

在继承时,我们通常会遇到这样一种场景,父类中的方法并不适合所有的子类。针对这种问题,我们通常有如下3种解决方法:

  1. 子类覆盖父类中的方法。会有如下问题:
  • 代码在多个子类中重复
  • 运行时的行为不容易改变
  • 父类改变时会牵一发而动全身
  • 很难知道所有子类的全部行为
  1. 把一些方法抽象成接口,而子类实现这些接口。会有如下问题:
  • 因为接口没有实现,所以会中造成重复代码变多
  1. 本文要采用的设计模式(策略模式)

设计原则

  1. 封装变化,找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起。
  2. 针对接口编程,而不是针对实现编程

针对接口编程真正的意思是针对超类型(supertpe)进行编程。针对接口编程,关键就在多态。利用多态,程序可以针对超类型编程,执行时会根据实际情况执行到真正的行为,不会被绑死在超类型的行为上。

  1. 多用组合,少用继承
  • 当你将两个类结合起来使用时,就是组合(composition)。鸭子的行为不是继承来的,而是和适当的行为对象”组合“来的。

实战

// parent class
public class Duck {
    // 将quackBehavior声明为接口类型(而不是具体类实现类型),每个鸭子对象都会动态地设置这些变量以在运行时引用正确的行为
    QuackBehavior quackBehavior;
    
    FlyBehavior flyBehavior;
    
    public void performQuack() {
        quackBehavior.quack();
    }
    
    public void performFfy() {
        flyBehavior.fly();
    }
    
    // 通过在超类中设置set方法,可以在运行时动态改变飞行的行为
    // 也就是使用组合建立系统具有很大的弹性,不仅可以将算法族封装成类。更可以在运行时动态地改变行为
    public void setFlyBehavior(FlyBehavior fb) {
        flyBehavior = fb;
    }
}
// child class
public class MallardDuck extends Duck {
    public MallardDuck() {
        // MallardDuck继承自Duck,所以具有相同的实例变量
        // quackBehavior在子类中被实例化成具体的对象,在执行performQuack()(在父类中定义)调用时,叫的职责被委托给Quack对象了。
        quackBehavior = new Quack();
        flyBehavior = new Fly();
        ...
    }
}
public static void main() {
    Duck mallardDuck = new MallardDuck();
    // 在运行时,动态地改变飞行的行为
    mallardDuck.setFlyBehavior(new FlyRocketPowered());
    mallardDuck.performFly();
    
}

鸭子的行为堪称是一族算法
== 未完,待续 ==

posted on 2019-11-21 20:09  harry1989  阅读(126)  评论(0编辑  收藏  举报

导航