设计模式-策略

来源:互联网 发布:找网络推手联系方式 编辑:程序博客网 时间:2024/04/28 17:10

写在前面

正在学习23种设计模式,打算把自己的理解总结起来,以此加深学习效果。这些总结会引用学习的书籍和网上的文献,加上自己的理解。文章的结构基本为:是什么为什么怎么做,因为如果理清了这三个问题,就理解的差不多了。

什么是策略模式

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

举个例子:我们的Duck类中有一个飞行行为,而在使用了策略模式之后,我们就不打算把fly()写在Duck类中了,而是把fly()方法封装到另一个FlyBehavior类中,使其独立于Duck类,而在使用的时候我们可以在Duck类中加一个performFly()方法,在这个方法里调用封装在FlyBehavior类的fly()方法,这样一旦我们对这个方法进行更改时,Duck的飞行行为也会变化,那么什么是相互替换呢?我们知道飞行行为可以有多种方式,让FlyBehavior成为接口,再加上几个其实现类,我们在调用时就可以动态决定使用哪种飞行方式,从而达到让让这些fly()算法能够相互替换。
解释概念可能有点抽象,下面通过具体例子阐述。

为什么要用策略模式

让我们设想一个场景:还是前面的鸭子Duck类,这个类会有一些基本属性,如鸭子的名称,还会有一些方法,如eat()。现在有各种鸭子,如家鸭,野鸭,天鹅等等。我们让其继承父类Duck,这样它就拥有基本属性和行为。现在有个需求:我们需要为其添加一个飞行行为,于是我们在父类Duck中添加fly()方法,这样所有鸭子都具有飞行行为了。

但是我们知道有的家鸭是不能飞的,于是我们想到行为应该用接口定义,让有飞行行为的鸭去实现这个接口,但是这么做又有了新问题,我们的代码复用性很差,不管fly()方法是否一样,每个鸭子子类都要写一遍fly()方法。

怎么用策略模式

策略模式就能解决这个问题。针对鸭的飞行行为,我们提炼出一个FlyBehavior接口,接口中有fly()方法,而让不同飞行方式,如FlywithWingsFlyNoWay去实现这个接口。即便我们有一百种鸭的子类,但是其飞行方式可能只有几种,这样就达到了代码的复用性。但是目前这几个飞行行为类并没有和Duck子类产生任何联系,于是我们在父类Duck中声明一个FlyBehavior接口类型的变量:FlyBehavior flyBehavior;,然后定义一个performFly()方法,方法里调用变量flyBehaviorfly()方法。这样子类只要是调用performFly()方法,就相当于调用我们之前抽出的fly()方法。到目前为止,我们实现了让Duck的任何子类不用编写任何飞行行为代码就能实现飞行,实现了代码复用性,而即便不能飞行的子类也有FlyNoWay提供给它。

但是等等,我们还只是调用接口FlyBehaviorfly()方法,没有指定具体实现类,还不能做到我想使用哪个飞行方式就使用哪个。于是我们在鸭子的子类如野鸭WildDuck类的构造方法中加上: flyBehavior = new FlywithWings();,这样就指定了其飞行方式为用翅膀飞行,同样的,在其他鸭子的子类构造方法中指定具体的飞行方式,即为flyBehavior变量实例化具体的FlyBehavior接口实现类。

这样之后,如果某种飞行方式需要更改,我们只需要对飞行行为实现类的fly()方法进行更改,就能让所有拥有该飞行方式的鸭子都更改生效。如果需要一种新的飞行方式,如机器鸭用机器进行飞行。我们只需定义一个FlyWithMachine类让其实现FlyBehavior接口的fly()方法。然后机器鸭MachineDuck的构造方法中指定:flyBehavior = new FlyWithMachine();。而如果想在运行时动态更换鸭子飞行方式,我们可以在Duck类中加一个set方法:

public void setFlyBehavior(FlyBehavior flyBehavior) {                            this.flyBehavior = flyBehavior;  }

从而达到动态调用setFlyBehavior方法更换飞行方式。

示例代码

//飞行行为接口public interface FlyBehavior {    public void fly();}//用翅膀的飞行方式public class FlyWithWings implements FlyBehavior{    @Override    public void fly() {        System.out.println("i am flying with wings");    }}//不会飞的飞行方式public class FlyNoWay implements FlyBehavior{    @Override    public void fly() {        // i can't fly,so i don't do anything...    }}//用机器的飞行方式public class FlyWithMachine implements FlyBehavior{    @Override    public void fly() {        System.out.println("i am flying with machine");    }}//鸭子父类public abstract class Duck {    protected String name;    protected FlyBehavior flyBehavior;    protected void eat(){        System.out.println("i am eating");    }    public void performFly(){        flyBehavior.fly();    }    public void setFlyBehavior(FlyBehavior flyBehavior) {        this.flyBehavior = flyBehavior;    }   }//家鸭public class HomeDuck extends Duck{    public HomeDuck(){        flyBehavior = new FlyNoWay();    }}//野鸭public class WildDuck extends Duck{    public WildDuck(){        flyBehavior = new FlyWithWings();    }}public class Main {    public static void main(String[] args) {        System.out.println("homeDuck尝试飞行:");        Duck homeDuck = new HomeDuck();        homeDuck.performFly();        System.out.println("wildDuck尝试飞行:");        Duck wildDuck = new WildDuck();        wildDuck.performFly();        System.out.println("wildDuck改用机器飞行:");        wildDuck.setFlyBehavior(new FlyWithMachine());        wildDuck.performFly();    }}

打印:
homeDuck尝试飞行:
wildDuck尝试飞行:
i am flying with wings
wildDuck改用机器飞行:
i am flying with machine

0 0
原创粉丝点击