设计模式-策略
写在前面
正在学习23种设计模式,打算把自己的理解总结起来,以此加深学习效果。这些总结会引用学习的书籍和网上的文献,加上自己的理解。文章的结构基本为:是什么,为什么,怎么做,因为如果理清了这三个问题,就理解的差不多了。
什么是策略模式
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
举个例子:我们的Duck类中有一个飞行行为,而在使用了策略模式之后,我们就不打算把fly()写在Duck类中了,而是把fly()方法封装到另一个FlyBehavior类中,使其独立于Duck类,而在使用的时候我们可以在Duck类中加一个performFly()方法,在这个方法里调用封装在FlyBehavior类的fly()方法,这样一旦我们对这个方法进行更改时,Duck的飞行行为也会变化,那么什么是相互替换呢?我们知道飞行行为可以有多种方式,让FlyBehavior成为接口,再加上几个其实现类,我们在调用时就可以动态决定使用哪种飞行方式,从而达到让让这些fly()算法能够相互替换。
解释概念可能有点抽象,下面通过具体例子阐述。
为什么要用策略模式
让我们设想一个场景:还是前面的鸭子Duck类,这个类会有一些基本属性,如鸭子的名称,还会有一些方法,如eat()。现在有各种鸭子,如家鸭,野鸭,天鹅等等。我们让其继承父类Duck,这样它就拥有基本属性和行为。现在有个需求:我们需要为其添加一个飞行行为,于是我们在父类Duck中添加fly()方法,这样所有鸭子都具有飞行行为了。
但是我们知道有的家鸭是不能飞的,于是我们想到行为应该用接口定义,让有飞行行为的鸭去实现这个接口,但是这么做又有了新问题,我们的代码复用性很差,不管fly()方法是否一样,每个鸭子子类都要写一遍fly()方法。
怎么用策略模式
策略模式就能解决这个问题。针对鸭的飞行行为,我们提炼出一个FlyBehavior接口,接口中有fly()方法,而让不同飞行方式,如FlywithWings,FlyNoWay去实现这个接口。即便我们有一百种鸭的子类,但是其飞行方式可能只有几种,这样就达到了代码的复用性。但是目前这几个飞行行为类并没有和Duck子类产生任何联系,于是我们在父类Duck中声明一个FlyBehavior接口类型的变量:FlyBehavior flyBehavior;,然后定义一个performFly()方法,方法里调用变量flyBehavior的fly()方法。这样子类只要是调用performFly()方法,就相当于调用我们之前抽出的fly()方法。到目前为止,我们实现了让Duck的任何子类不用编写任何飞行行为代码就能实现飞行,实现了代码复用性,而即便不能飞行的子类也有FlyNoWay提供给它。
但是等等,我们还只是调用接口FlyBehavior的fly()方法,没有指定具体实现类,还不能做到我想使用哪个飞行方式就使用哪个。于是我们在鸭子的子类如野鸭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

浙公网安备 33010602011771号