策略模式属于行为型模式
这里以一个例子来进行引入并讲解。该例子是一个鸭子游戏,游戏中会出现各种各样的鸭子,它们会游泳和呱呱叫,这样我们会发现,它们的共同特征是游泳和呱呱叫,所以我们可以设计一个超类,然后其它子类继承该超类即可。
在这里我们对超类进行设计时,需要有三个方法,其一是swim(),其二是quack(),其三就是外观display()了,这里的外观是各种各样的,所以外观需要是抽象的,这里给出超类的源码
public abstract class Duck {
public void quack() {
System.out.println("呱呱叫");
}
public void swim() {
System.out.println("游泳");
}
public abstract void display();
}
有了超类,我们就可以设计子类了,如果我们想要设计一只绿头鸭和一只红头鸭,那么只需继承超类即可
public class MallardDuck extends Duck {
@Override
public void display() {
System.out.println("我是绿头鸭");
}
}
public class RedheadDuck extends Duck {
@Override
public void display() {
System.out.println("我是红头鸭");
}
}
这样看似没什么问题,但是,如果有的鸭子不会叫怎么办呢,你可能会想,让不会叫的鸭子重写quack()方法,如果将来又有鸭子会飞呢,你可能会在超类中加上fly()方法,但是有的鸭子又不会飞,你又要重写该fly()方法,这里给出超类和一个既不会叫也不会飞的子类鸭子
public abstract class Duck {
public void quack() {
System.out.println("呱呱叫");
}
public void fly() {
System.out.println("飞");
}
public void swim() {
System.out.println("游泳");
}
public abstract void display();
}
public class NoQuackNoFly extends Duck {
@Override
public void display() {
System.out.println("我不会叫也不会飞");
}
//因为既不会叫也不会飞,所以只能空实现
@Override
public void quack() {
}
@Override
public void fly() {
}
}
如果后面还有更多的方法是不是都需要重写一遍,这看似有点麻烦了,所以我们可以将这些非共有的方法进行分离开来,然接口来处理这些方法,有该方法的我们就去实现,没有的就不用实现了,改完之后的Duck(),以及两个接口如下
public abstract class Duck {
public void swim() {
System.out.println("游泳");
}
public abstract void display();
}
public interface Quack {
public void quack();
}
public interface Fly {
public void fly();
}
这样一来,我们再去实现既不会飞也不会叫的鸭子就相对简单了,如下
public class NoQuackNoFly extends Duck {
@Override
public void display() {
System.out.println("我不会叫也不会飞");
}
}
这看似很棒,但是,如果有1024只鸭子,它们都重写了quack方法,而且都是呱呱叫,如果我们想让呱呱叫改为吱吱叫,那你是不是要改1024个类,这貌似有点笨拙,所以我们引入了我们的策略模式进行解决
首先我们有一个超类,也就是Duck,里面有两个 固定的方法,一个是游泳,一个是外观
public abstract class Duck {
public void swim() {
System.out.println("游泳");
}
public abstract void display();
}
然后是叫和飞的接口
public interface Quack {
public void quack();
}
public interface Fly {
public void fly();
}
这里我们用不同方法的类去实现这两个接口,你会看到神奇的效果的
public class QuackImpl implements Quack {
@Override
public void quack() {
System.out.println("我会呱呱叫");
}
}
public class SquackImpl implements Quack {
@Override
public void quack() {
System.out.println("我会吱吱叫");
}
}
public class FlyImpl implements Fly {
@Override
public void fly() {
System.out.println("我会飞");
}
}
接口的实现类写好之后,我们以叫声来进行测试,我们以绿头鸭是呱呱叫红头鸭是吱吱叫为例,此刻我们修改Duck类,添加对叫声的引用
public abstract class Duck {
Quack quack;
public void performQuack() {
quack.quack();
}
public void swim() {
System.out.println("游泳");
}
public abstract void display();
}
然后我们去修改绿头鸭和红头鸭的构造方法,在构造方法中new出叫声的实例对象,也就构成了,当你调用quack()方法时,我们好知道是调用的呱呱叫还是吱吱叫
public class MallardDuck extends Duck {
public MallardDuck() {
quack = new QuackImpl();
}
@Override
public void display() {
System.out.println("我是绿头鸭");
}
}
public class RedheadDuck extends Duck {
public RedheadDuck() {
quack = new SquackImpl();
}
@Override
public void display() {
System.out.println("我是红头鸭");
}
}
好了,这里给出测试类Main
public class Main {
public static void main(String[] args) {
Duck duck = new MallardDuck();
duck.performQuack();
Duck duck1 = new RedheadDuck();
duck1.performQuack();
}
}
运行结果如下