【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
策略模式是一种这样的模式,其通过接口定义一种算法规范,而实现该接口的类就是一组算法,对于使用者而言,其只需要根据该接口定义的规范来使用该接口的一个实例即可,而具体的算法则是由传入该使用者的对应于该接口的具体实现的类来执行的。
假如现在我们要设计这样一个系统,有一组鸭子,比如真实世界的鸭子,橡皮鸭和木鸭。这三种鸭子都是鸭子种类的一种,并且都会游泳,但是只有真实的鸭子会飞,会叫,而橡皮鸭只会叫,不会飞,木鸭则不会飞也不会叫。为了设计一个灵活的并且可扩展的系统,使用继承是不可以的。首先,如果我们为超类定义飞和叫的方法,那么橡皮鸭和木鸭也都会飞和叫了;其次,如果我们只是将飞和叫的方法定义在相应的子鸭类中的话,就把各个子类给孤立起来了,如果有一种新的鸭类,其是和现有系统中某种鸭类的叫法或飞行方式相同,那么其只能定义自己的飞或者叫的方法,而不能达到复用的目的,并且由于飞和叫是子类孤立的行为,那么在使用该系统时也就无法基于多态来设计新的系统了。
对于上面的系统,系统中变化的部分是鸭子这个主体,以及鸭子都会游泳,因而我们可以将其放在一个超类中。变化的部分主要是不是所有的鸭子都会飞,也不是所有的鸭子都会叫。那么我们可以将变化的部分抽离出来,但是我们也不能只是单纯的声明一个Fly类来表示鸭子是否会飞,因为鸭子飞行的方式有可能不同,比如火箭鸭就可以进行喷气式飞行;同理,并不是所有的鸭子的叫声都是一样的,有的鸭子发出的声音是“吱吱吱”,有的则发出“呱呱呱”的叫声。这里我们就使用到了策略模式,我们可以定义一种表示飞这种行为的接口,并且可以定义一种表示叫这种行为的接口。对于飞这种行为,则可以有多种实现,比如不会飞行,简单的飞行和喷气式飞行;对于叫这种行为,可以定义不会叫,“呱呱叫”和“吱吱叫”三种实现。最后我们这两组算法族的接口的实例通过组合的方式分别封装到鸭子主体中,表示这个鸭子具有飞和叫这两种行为。这里鸭子主体是一个抽象类,而具体的鸭子则在其实现中,并且在具体的鸭子实现中对鸭子的具体以某种方式飞行和以某种方式叫来进行定制,这样就可以产生出一个独有特征的鸭子类型。
整个系统的类图如下:

具体的实现类如下:
飞行算法接口:
public interface FlyBehavior {
void fly();
}
飞行算法实现:
public class FlyNoWay implements FlyBehavior {
@Override
public void fly() {
System.out.println("I cannot fly. ");
}
}
public class FlyWithWings implements FlyBehavior {
@Override
public void fly() {
System.out.println("I'm flying!! ");
}
}
public class FlyRocketPowered implements FlyBehavior {
@Override
public void fly() {
System.out.println("I'm flying with a rocket!");
}
}
叫法算法接口:
public interface QuackBehavior {
void quack();
}
叫法算法实现:
public class MuteQuack implements QuackBehavior {
@Override
public void quack() {
System.out.println("<< Silence >>");
}
}
public class Quack implements QuackBehavior {
@Override
public void quack() {
System.out.println("Quack");
}
}
鸭子主体类抽象类:
public abstract class Duck {
protected QuackBehavior quackBehavior;
protected FlyBehavior flyBehavior;
public abstract void display();
public void performQuack() {
quackBehavior.quack();
}
public void performFly() {
flyBehavior.fly();
}
public void swim() {
System.out.println("All ducks float, even decoys! ");
}
public void setQuackBehavior(QuackBehavior quackBehavior) {
this.quackBehavior = quackBehavior;
}
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
}
具体的鸭子实现:
public class MallardDuck extends Duck {
public MallardDuck() {
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
@Override
public void display() {
System.out.println("I'm a real Mallard duck.");
}
}
public class ModelDuck extends Duck {
public ModelDuck() {
flyBehavior = new FlyNoWay();
quackBehavior = new Quack();
}
@Override
public void display() {
System.out.println("I'm a model duck");
}
}
通过策略模式设计的上述系统,对于扩展是非常方便的,比如现在有一种新的飞行行为,那么我们只需要创建FlyBehavior接口的一个实现即可,而在具体的鸭子实现中对其进行组装,这样就可以达到变换算法的目的。在鸭子主体类中,我们添加了两个设值方法,这两个方法的目的是在运行的时候可以动态的改变鸭子的飞行方式,也即实现策略,使得该系统更加的灵活。
本文介绍策略模式在设计鸭子行为系统中的应用。通过定义飞行和叫声接口及其实现,实现了不同鸭子的不同行为。文章详细展示了如何利用策略模式提高代码的灵活性和扩展性。
1205

被折叠的 条评论
为什么被折叠?



