策略模式

Java设计模式之策略模式

前言:

最近在学习设计模式,看的书是《Head First 设计模式》首先介绍的就是策略模式(Strategy),我将结合书中描述的加上自己理解在此记录一下。

概念:

策略模式定义了算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。我理解的是在处理某类业务时,将平等出现的情况封装起来,根据自己的需要去调用,这样也避免代码中出现大量的if-else,当然使用这些算法之前我们得了解每个算法的含义。

策略模式结构

策略模式涉及三个角色:
1、环境角色:持有一个Strategy的引用
2、抽象策略角色:通常是由一个接口或者抽象类实现。此角色给出所有的具体策略类所需的接口。
3、具体策略角色:包装了相关的算法和行为。

quackBehavior(叫行为)

代码

不同的鸭子有不一样的叫法(quack)(呱呱叫,吱吱叫,不会叫),不一样的飞行方法(fly)(翅膀飞,不会飞)
也就是Duck类内的fly()和quack()会随着鸭子的不同而改变,为了要把这两个行为从Duck类中分开,建立一组新类来代表每个行为。

首先有个鸭子类(Duck),飞行和叫这两个行为变量为接口类型,下面有这两个接口。所有的鸭子都会游泳(假设都会游泳,但你要硬是抬杠,旱鸭子不会游泳我就没办法了),游泳这个方法就不抽取了。

public abstract class Duck {
   FlyBehavior flyBehavior;//飞行行为,接口类型
   QuackBehavior quackBehavior;//叫行为,接口类型
   public Duck(){
   }
   public void performQuack(){
      quackBehavior.quack();
   }
   public void performFly(){
      flyBehavior.fly();
   }
   public void swim(){
      System.out.println("游泳");
   }
   public void setFlyBehavior(FlyBehavior fb) {
      flyBehavior = fb;
   }
   public void setQuackBehavior(QuackBehavior qb) {
      quackBehavior = qb;
   }
}

飞行行为接口及其实现类

public interface FlyBehavior {
    void fly();
}
public class FlyWithWings implements FlyBehavior {
    @Override
    public void fly() {
        System.out.println("翅膀飞的鸭子");
    }
}
public class FlyNoWay implements FlyBehavior {
    @Override
    public void fly() {
        System.out.println("不会飞");
    }
}
public class FlyRocketPowered implements FlyBehavior {
    @Override
    public void fly() {
        System.out.println("用火箭助推器飞");
    }
}

叫行为接口及其实现类

public interface QuackBehavior {
    void quack();
}
public class Quack implements QuackBehavior{
    @Override
    public void quack() {
        System.out.println("呱呱叫");
    }
}
public class Squack implements QuackBehavior{
    @Override
    public void quack() {
        System.out.println("吱吱叫");
    }
}
public class MuteQuack implements QuackBehavior{
    @Override
    public void quack() {
        System.out.println("什么都不做,不会叫");
    }
}

写到这里整个策略模式的架子就算搭建好了,Duck类有两个接口类型的行为变量,两个行为接口以及他们各自三个实现类,不同的鸭子怎么叫怎么飞 我们就直接调用就可以了。

测试

新建一个绿头鸭类 MallardDuck 继承Duck类,这是一只正常的鸭子会叫还会飞,既然是正常的那就new一个正常叫的行为和一个正常飞的行为。

public class MallardDuck extends Duck{
    public MallardDuck(){
        quackBehavior = new Quack();//正常的呱呱叫
        flyBehavior = new FlyWithWings();//用翅膀飞

    }
    public void display(){
        System.out.println("我是绿头鸭");
    }
}

测试MallardDuck

public class MiniDuckSimulator {
    public static void main(String[] args) {
        MallardDuck mallard = new MallardDuck();
        mallard.performFly();
        //调用performFly()方法会被委托给flyBehavior对象(也就是FlyWithWings实例),该对象是在绿头鸭构造器中设置的
        mallard.performQuack();
        //同上,叫的行为也是在绿头鸭的构造器中设置的。
    }
}

结果
翅膀飞的鸭子
呱呱叫

注意

Duck类中有两个set方法,可以设定鸭子的行为,现在用个模型鸭(ModelDuck)举例子

public class ModelDuck extends Duck {
    public ModelDuck(){
        flyBehavior = new FlyNoWay();
        quackBehavior = new Quack();
    }
    public void display(){
        System.out.println("我是模型鸭子");
    }
}
public class MiniDuckSimulator {
    public static void main(String[] args) {
        ModelDuck model = new ModelDuck();
        model.performFly();//现在不会飞
        model.setFlyBehavior(new FlyRocketPowered());//把想用的飞行方法传进去,模型鸭就有这种飞行模式。
        model.performFly();//加上火箭助推器飞行行为那不得起飞了啊。
    }
}

运行结果
我是不会飞的鸭子
用火箭助推器飞
在运行时想要改变鸭子的行为,只需调用鸭子的setter方法就可以了。

总结

策略模式的重心不是如何实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活,具有更好的维护性和扩展性。