策略模式
基本介绍
策略模式的策略,该怎么理解呢?在我看来,就是在面对不同的场景,采取不一样的处理方式
策略模式属于行为型模式,大多应用于动态在一个对象的多种行为进行切换的场景。
意图:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换,以避免在多种算法相似的场景下,使用过多的 if…else 所带来的复杂和难以维护
注意:当一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题
假设有一家游戏公司,委托我们开发一款模拟鸭子池塘的游戏,该公司的主要产品是一种可以模拟展示多种会游泳和嘎嘎叫的鸭子的游戏,它们要求在设计鸭子时尽量贴近生活,保持真实性。
他们的最初始的设计如下:
鸭子的抽象类
public abstract class Duck {
public Duck() {}
public abstract void display();// 显示鸭子信息
public void quack() {
System.out.println("鸭子嘎嘎叫");
}
public void swim() {
System.out.println("鸭子会游泳");
}
public void fly() {
System.out.println("鸭子会飞翔");
}
}
北京鸭
public class PekingDuck extends Duck {
@Override
public void display() {
System.out.println("北京鸭");
}
/**
* 由于北京鸭不会飞翔,因此需要重写fly
*/
@Override
public void fly(){
System.out.println("北京鸭不会飞翔");
}
}
玩具鸭
public class ToyDuck extends Duck {
@Override
public void display() {
System.out.println("玩具鸭");
}
@Override
public void quack() {
System.out.println("玩具鸭不能叫~~~");
}
@Override
public void fly() {
System.out.println("玩具鸭不会飞翔~~");
}
}
野鸭
public class WildDuck extends Duck {
@Override
public void display() {
System.out.println("这是野鸭");
}
}
利用继承来复用鸭子的各个行为,初衷是好的,但是没有真正将鸭子的各个行为拆分,只是简单的复用,就会有很多问题。
当我们需要新添加一类鸭子,若其父类的抽象方法不满足当前对象时,我们就需要重写以覆盖父类的抽象方法,这就违背了里式替换原则且扩展性欠缺。
策略模式
刚刚我们也说了,策略模式主要应用 动态在一个对象的多种行为进行切换的场景
那我们开始重新构建模拟鸭子的这款游戏吧,我们想一想能不能把鸭子的各种行为抽出来再跟鸭子进行组合, 这样在面对不同的鸭子时进行组装即可
鸭子的抽象类
public abstract class Duck {
//属性,策略接口
FlyBehavior flyBehavior;
public Duck() {}
public abstract void display();// 显示鸭子信息
public void quack() {
System.out.println("鸭子嘎嘎叫");
}
public void swim() {
System.out.println("鸭子会游泳");
}
public void fly() {
if(flyBehavior != null){
flyBehavior.fly();
}
}
}
飞行行为
public interface FlyBehavior {
void fly();
}
行为-飞的好
public class GoodFlyBehavior implements FlyBehavior {
@Override
public void fly() {
System.out.println("飞翔技术高超");
}
}
行为-飞的一般
public class NormalFlyBehavior implements FlyBehavior {
@Override
public void fly() {
System.out.println("飞翔技术一般");
}
}
行为-不会飞
public class NoFlyBehavior implements FlyBehavior {
@Override
public void fly() {
System.out.println("不会飞翔");
}
}
北京鸭
public class PekingDuck extends Duck {
public PekingDuck(){
//给鸭子赋予飞的一般的行为
flyBehavior = new NormalFlyBehavior();
}
@Override
public void display() {
System.out.println("北京鸭");
}
}
野鸭
public class WildDuck extends Duck {
public WildDuck() {
//给鸭子赋予飞的好的行为
flyBehavior = new GoodFlyBehavior();
}
@Override
public void display() {
System.out.println("这是野鸭");
}
}
玩具鸭
public class ToyDuck extends Duck {
public ToyDuck(){
//给鸭子赋予不会飞的行为
flyBehavior = new NoFlyBehavior();
}
@Override
public void display() {
System.out.println("玩具鸭");
}
@Override
public void quack() {
System.out.println("玩具鸭不能叫~~~");
}
}
从上述的例子我们看出,将鸭子的各个行为组合到不同的鸭子中去,既增加了系统的弹性,也满足了每个鸭子的特点。
鸭子会不会飞,飞的好不好根据不同的策略制定。
综上: 策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为
JDK-Arrays的应用
在jdk中, Arrays 的Comparator 就实现了策略模式
public class Arrays {
public static <T> void sort(T[] a, Comparator<? super T> c) {
if (c == null) {
sort(a);
} else {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, c);
else
TimSort.sort(a, 0, a.length, c, null, 0, 0);
}
}
}
public interface Comparator<T> {
int compare(T o1, T o2);
}
我们测试一下:
public class TestStrategy {
public static void main(String[] args) {
// 数组
Integer[] data = { 9, 1, 2, 8, 4, 3 };
// 实现降序排序,返回-1放左边,1放右边,0保持不变
// 说明
// 1. 实现了 Comparator 接口(策略接口) , 匿名类 对象 new Comparator<Integer>(){..}
// 2. 对象 new Comparator<Integer>(){..} 就是实现了 策略接口 的对象
// 3. public int compare(Integer o1, Integer o2){} 指定具体的处理方式
Comparator<Integer> comparator = new Comparator<Integer>() {
public int compare(Integer o1, Integer o2) {
if (o1 > o2) {
return -1;
} else {
return 1;
}
};
};
// 说明
/*
* public static <T> void sort(T[] a, Comparator<? super T> c) { if (c == null)
* { sort(a); //默认方法 } else { if (LegacyMergeSort.userRequested)
* legacyMergeSort(a, c); //使用策略对象c else // 使用策略对象c TimSort.sort(a, 0, a.length,
* c, null, 0, 0); } }
*/
// 方式1
Arrays.sort(data, comparator);
System.out.println(Arrays.toString(data)); // 降序排序
// 方式2- 同时lambda 表达式实现 策略模式
Integer[] data2 = { 19, 11, 12, 18, 14, 13 };
Arrays.sort(data2, (var1, var2) -> {
if (var1.compareTo(var2) > 0) {
return -1;
} else {
return 1;
}
});
System.out.println("data2=" + Arrays.toString(data2));
}
}