策略模式
策略模式
鸭子问题:
- 有各种各样的鸭子(野鸭,玩具鸭,北京鸭)
- 显示鸭子的信息
传统方式的解决方式
- 将鸭子作为一个抽象类(Duck),将鸭子的特性抽取出来;
- 然后各种鸭子继承Duck
传统方式的代码实现:
//抽象出来的鸭子
public abstract class Duck { public Duck() { } public void quack(){ System.out.println("鸭子嘎嘎叫"); } public void swim(){ System.out.println("鸭子会游泳!!!"); } public void fly(){ System.out.println("鸭子会飞!!!!"); } public abstract void display();//用来显示鸭子信息的方法 }
//野鸭
package com.atguigu.show.pojo; public class WildDuck extends Duck { @Override public void display() { System.out.println("这是只野鸭!!!"); } }
//北京鸭
public class BeiJingDuck extends Duck { @Override public void display() { System.out.println("这是北京鸭!!!"); } @Override public void fly() { System.out.println("北京鸭进了炉子,不能飞的!!!!"); } }
//玩具鸭
public class PlayDuck extends Duck { @Override public void display() { System.out.println("玩具鸭"); } //注意此时玩具鸭被认为是不具备鸭子的"飞,叫,游泳"的特性需要重写所有的方法 }
传统方法的问题:
- 其他鸭子都继承了Duck,所以让所有的子类都会fly;[对类的局部改动,尤其是超类的局部改动,会影响其他部分,这是由继承所导致的溢出效应]
- 问题的解决方案就是采用覆盖的方式====>重写父类的方法
- 但是若是部分的子类和父类的行为完全不同,就会导致需要重写父类的全部方法;
- 在此处就可以利用策略模式(strategy pattern)
策略模式的思路:
将继承转换成为组合或者聚合;
定义算法的族,分别封装起来,让他们之间可以相互的替换,此模式让算法的变化独立于使用算法发客户;
体现的设计原则:
- 把变化的代码从不变的代码中分离出来;
- 针对接口编程而不是具体的类;
- 多使用组合/聚合少使用继承(用户通过组合的方式使用策略).
策略模式的原理图
注意在Context中可以有多个策略接口的属性
从示意图可以看出:客户拥有变量strategy或者其他的策略接口;
至于使用到哪个策略----->可以在构造器中进行指定;
使用策略模式解决鸭子问题
思路分析:
- 先写出策略接口
- 写出Duck类,将策略接口聚合或者组合
- 由实现类实现Duck类
代码实现:
//抽象出策略接口
public interface FlyBehavior { void fly(); }
//定义不同策略的实现
实现一:
public class GoodFlyBehavior implements FlyBehavior { @Override public void fly() { System.out.println("飞翔技术高超!!!!"); } }
实现二:
public class NoFlyBehavior implements FlyBehavior { @Override public void fly() { System.out.println("不会飞行!!!!"); } }
//改进一下Duck类的fly方法,并且将策略接口聚合到Duck
public abstract class Duck { public Duck() { } public void quack(){ System.out.println("鸭子嘎嘎叫"); } public void swim(){ System.out.println("鸭子会游泳!!!"); } //策略接口 FlyBehavior flyBehavior; //改写获取fly的方式 public void fly(){ //改进fly方法 if (flyBehavior != null){ //调用自己的fly方法 flyBehavior.fly(); } } public abstract void display();//用来显示鸭子信息的方法 }
//具体的实现
public class BeiJingDuck extends Duck { //通过构造器的方式给 flyBehavior 赋值 public BeiJingDuck() { flyBehavior = new NoFlyBehavior(); } @Override public void display() { System.out.println("这是北京鸭!!!"); } }
策略模式在JDK中的分析
在Arrays中使用到了策略模式:
public class Strategy { public static void main(String[] args) { Integer[] data = {9,5,6,2,3,5,2,1}; /** * 说明: * 可以认为Comparator就是一个策略接口,而对应的匿名内部类就是策略的实现 */ Comparator<Integer> comparable = new Comparator<Integer>(){ @Override//指定的处理方式 public int compare(Integer o1, Integer o2) { if (o1 > o2){ return 1; }else { return -1; } } }; Arrays.sort(data,comparable); System.out.println(Arrays.toString(data)); } } //结果:[1, 2, 2, 3, 5, 5, 6, 9] 是升序的
Arrays.sort(data,comparable);方法的源码
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 TimSort.sort(a, 0, a.length, c, null, 0, 0); } }
这里就是一个很经典的策略模式