策略模式

策略模式

鸭子问题:

  1. 有各种各样的鸭子(野鸭,玩具鸭,北京鸭)
  2. 显示鸭子的信息

传统方式的解决方式

  1. 将鸭子作为一个抽象类(Duck),将鸭子的特性抽取出来;
  2. 然后各种鸭子继承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("玩具鸭");
    }

    //注意此时玩具鸭被认为是不具备鸭子的"飞,叫,游泳"的特性需要重写所有的方法
}

传统方法的问题:

  1. 其他鸭子都继承了Duck,所以让所有的子类都会fly;[对类的局部改动,尤其是超类的局部改动,会影响其他部分,这是由继承所导致的溢出效应]
    • 问题的解决方案就是采用覆盖的方式====>重写父类的方法
  2. 但是若是部分的子类和父类的行为完全不同,就会导致需要重写父类的全部方法;
    • 在此处就可以利用策略模式(strategy pattern)

策略模式的思路:

将继承转换成为组合或者聚合;

定义算法的族,分别封装起来,让他们之间可以相互的替换,此模式让算法的变化独立于使用算法发客户;

体现的设计原则:

  1. 把变化的代码从不变的代码中分离出来;
  2. 针对接口编程而不是具体的类;
  3. 多使用组合/聚合少使用继承(用户通过组合的方式使用策略).

策略模式的原理图

注意在Context中可以有多个策略接口的属性

从示意图可以看出:客户拥有变量strategy或者其他的策略接口;

至于使用到哪个策略----->可以在构造器中进行指定;

使用策略模式解决鸭子问题

思路分析:

  1. 先写出策略接口
  2. 写出Duck类,将策略接口聚合或者组合
  3. 由实现类实现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);
        }
    }

这里就是一个很经典的策略模式

posted @ 2022-11-13 22:36  鸽宗  阅读(55)  评论(0编辑  收藏  举报