设计模式之策略模式

1. 介绍

策略模式定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化不会影响到客户端。从概念上看,这些算法完成的功能都是一样的,只不过是具体的实现不一样,使用策略模式可以让相同的方式调用所有的算法,减少了各种算法与使用算法类之间的耦合。

策略模式类图

优点
① 简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
② 简化了客户端代码,消除了多个if-else的判断;
③ 实现的选择 Strategy模式可以提供相同行为的不同实现。客户可以根据不同时间/空间权衡取舍要求从不同策略中进行选择。
缺点
① 会产生很多的策略类,每个策略都需要对应一个策略类;
② 提前需要知道有哪些策略,需要从中选择,指定最终执行的策略。
适用场景
① 许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。即一个系统需要动态地在几种算法中选择一种。
② 需要使用一个算法的不同变体。例如,你可能会定义一些反映不同的空间 /时间权衡的算法。当这些变体实现为一个算法的类层次时 ,可以使用策略模式。
③ 算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。
④ 一个类定义了多种行为 , 并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的Strategy类中以代替这些条件语句。

2. 应用案例

现在我们需要设计一款玩具汽车,具有基本的鸣笛和行驶的功能。
玩具汽车的超类如下:

public abstract class Car {
    public Car(){
    }
    public abstract void display();
    public void whistle(){
        System.out.println("所有的汽车都会鸣笛");
    }
    public void run(){
        System.out.println("所有的汽车都会行驶");
    }
}

玩具汽车具体实现类如下:

public class ToyCar extends Car {
    @Override
    public void display() {
        System.out.println("这是玩具车!");
    }
}
public class Benz extends Car {
    @Override
    public void display() {
        System.out.println("这是私家车!");
    }
}

其他实现省略。

需求变动:玩具车需要具有飞行功能

简单的修改

在超类中新增fly方法,让所有的汽车都具备飞行的能力

public abstract class Car {
    //其他方法省略
    public void fly(){
        System.out.println("所有的汽车都会飞");
    }
}

产生的问题:绝大部分汽车本身不能飞,但是在Car类中添加了fly方法,却错误的赋予了它们飞行的能力,比如,奔驰车Benz,超类中新加的方法,会影响所有子类的行为。

简单的解决办法:最简单的解决办法就是利用方法的复写@Override,复写fly方法,根据不同汽车的特性去实现不同的fly。(缺陷:每新加一种汽车,可能就会去复写超类的方法,如,加入一只木制汽车,它可能既不会飞行,又不能发出声音,而且随着种类越多,那么复写的次数越多,重复的代码也就会越多,后期维护的时候可能就需要同时改很多个地方)

设计原则:应用中可能会产生变化之处,要把它们独立出来,不要和不需要变化的代码放在一处(不变化的代码一般是稳定的,加入变化的代码之后很可能就会破坏原来的稳定性)

独立变化的修改

变化的部分:飞行行为,鸣笛行为

//飞行行为
public interface FlyBehavior {
    void fly();
}
//鸣笛行为
public interface WhistleBehavior {
    void whistle();
}

Car超类修改

public abstract class Car {

    private FlyBehavior flyBehavior;
    private WhistleBehavior whistleBehavior;
    public abstract void display();

    public Duck(FlyBehavior flyBehavior, WhistleBehavior whistleBehavior) {
        this.flyBehavior = flyBehavior;
        this.whistleBehavior = whistleBehavior;
    }
    public void fly() {
        flyBehavior.fly();
    }
    public void whistle() {
        whistleBehavior.whistle();
    }
    public void run() {
        System.out.println("所有汽车都会行驶");
    }
    // 加入set方法后就可以随时调用这两个方法来改变汽车的行为(策略模式的精髓,算法之间的相互替换)
    public void setFlyBehavior(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }
    public void setWhistleBehavior(WhistleBehavior whistleBehavior) {
        this.whistleBehavior = whistleBehavior;
    }
}

Fly接口的实现类

  1. 不会飞行:
public class FlyNoWay implements FlyBehavior {
    @Override
    public void fly() {
        System.out.println("我无法飞行");
    }
}
  1. 可以飞行
public class FlyWithPower implements FlyBehavior {
    @Override
    public void fly() {
        System.out.println("我能够飞行");
    }
}

鸣笛行为实现类

  1. 不会鸣笛
public class MuteWhistle implements WhistleBehavior {
    @Override
    public void whistle() {
        System.out.println("无法鸣笛");
    }
}
  1. 可以鸣笛
public class Whistle implements WhistleBehavior {
    @Override
    public void whistle() {
        System.out.println("滴滴滴~");
    }
}

具体的汽车类(玩具汽车)

public class ToyCar extends Car {

    //在超类中有setFlyBehavior,setQuakBehavior,同样允许客户端自己选择
    public ToyCar() {
        super(new FlyWhithPower(), new Whistle());
    }
    @Override
    public void display() {
        System.out.println("这是一辆玩具汽车");
    }
}

现在每辆汽车的鸣笛和飞行都可以自己选择灵活配置,不仅可以切换汽车,还可以切换汽车的行为,这在原来的设计上是办不到的,现在加一种新的汽车变得很简单了,而且不会对原来的设计造成影响。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一直想把常见的设计模式系统地学习一遍,结果和大多数人一样,过了几天就没能坚持下去了。我发现学习这件事情急不得,往往...
    Neulana阅读 579评论 5 2
  • 策略模式,是我们接触到的第一个设计模式,也是较容易理解的一个模式。我们可以给它下一个定义:** 定义了算法族,分别...
    六尺帐篷阅读 742评论 0 8
  • 策略模式定义算法族 , 分别封装起来,从而使得它们可以相互替换。策略模式使得算法的变化独立于使用算法的客户端。 分...
    在下喵星人阅读 388评论 3 1
  • 策略模式 大多数问题都可以使用多种方法来解决。以排序问题为例,对于以一定次序把元素放入一个列表,排序算法有很多。通...
    英武阅读 1,854评论 0 50
  • 今天的风像画了淡妆的空姐,清淡优雅,人人感到舒畅 而我的心口,有些不顺畅,有几丝心慌,几缕惆怅,动力有些不足,不知...
    柠檬珍阅读 274评论 0 4