学习记录之策略模式——行为型模式


一.引例

编写一个展示各种鸭子信息的项目,具体要求如下:

  1. 有各种鸭子——野鸭、水鸭、玩具鸭
  2. 鸭子有各种技能——叫、游泳、飞行
  3. 野鸭上述三个技能都会,水鸭不会飞行,玩具鸭不会游泳、飞行
  4. 要求输出各种鸭子技能的掌握情况

二、传统方案实现

传统的设计方案:构建一个抽象父类 Duck,并让各个子类(即各种鸭子)去继承Duck

代码演示:

	// 抽象父类
	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 WildDuck extends Duck{
    
    @Override
    public void display() {
        System.out.println("野鸭"); // 野鸭三个技能都会,因此不需要重写父类的三个方法
    }
}
public class Teal extends Duck{
    @Override
    public void display() {
        System.out.println("水鸭");
        quack();
        swim();
        fly();
    }

    @Override
    public void fly() {
        System.out.println("鸭子不会飞!!!");
    }
}
public class ToyDuck extends Duck{
    @Override
    public void display() {
        System.out.println("玩具鸭");
        quack();
        swim();
        fly();
    }

    @Override
    public void swim() {
        System.out.println("鸭子不会游泳");
    }

    @Override
    public void fly() {
        System.out.println("鸭子不会飞");
    }
}

客户端使用:

public class Client {
    public static void main(String[] args) {
        WildDuck wildDuck = new WildDuck();
        wildDuck.display();

        Teal teal = new Teal();
        teal.display();

        ToyDuck toyDuck = new ToyDuck();
        toyDuck.display();
    }
}

三、传统方案的问题分析

  1. 各种鸭子都继承了Duck类,所以fly()让所有鸭子都会飞,这是不正确的。
  2. 上面的问题是继承带来的,我们可以通过重写fly()来解决。
  3. 但如果又有一个木头鸭,就需要重写所有Duck类方法。
  4. 解决思路:策略模式

四、策略模式基本介绍

  • 策略模式中,定义算法簇(策略组),分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户

  • 体现的设计原则:
    1. 把变化的代码从不变的代码中分离出来;
    2. 针对接口编程而不是具体类(定义了策略接口);
    3. 多用组合/聚合,少用继承(客户端通过组合方式使用策略);

  • 策略模式的原理类图
    在这里插入图片描述

五、策略模式解决鸭子问题

思路分析:分别封装行为接口,实现算法簇,超类里放行为接口对象,在子类里具体设定行为对象。原则是:分离变化部分,封装接口,基于接口编程各种功能。此模式让行为的变化独立于算法的使用者。
在这里插入图片描述
代码演示,仅演示飞行功能,其余功能类似。

public interface FlyBehavior {
    void fly(); // 子类具体实现
}
public class GoodFlyBehavior implements FlyBehavior{
    @Override
    public void fly() {
        System.out.println("飞行技术高超");
    }
}
public class BadFlyBehavior implements FlyBehavior{
    @Override
    public void fly() {
        System.out.println("飞行技术一般般");
    }
}
public class NoFlyBehavior implements FlyBehavior{
    @Override
    public void fly() {
        System.out.println("不会飞行");
    }
}
public abstract class Duck {

    //属性,策略接口
    FlyBehavior flyBehavior;

    public Duck() {

    }

    public abstract void display();

    public void fly(){
        try {
            flyBehavior.fly();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void setFlyBehavior(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }
}
public class WildDuck extends Duck{
    public WildDuck(){
        flyBehavior = new GoodFlyBehavior();
    }
    @Override
    public void display() {
        System.out.println("野鸭");
        flyBehavior.fly();
    }
}
public class ToyDuck extends Duck{
    public ToyDuck(){
        flyBehavior = new NoFlyBehavior();
    }
    @Override
    public void display() {
        System.out.println("玩具鸭");
        flyBehavior.fly();
    }
}

public class Client {
    public static void main(String[] args) {
        WildDuck wildDuck = new WildDuck();
        wildDuck.display();

        ToyDuck toyDuck = new ToyDuck();
        toyDuck.display();

        // 动态改变某个对象的行为
        toyDuck.setFlyBehavior(new BadFlyBehavior());
        toyDuck.display();
    }
}
野鸭
飞行技术高超
玩具鸭
不会飞行
玩具鸭
飞行技术一般般

六、策略模式在JDK-Arrays中的应用

  • JDK的Arrays的Comparator使用了策略模式
  • 代码演示:
public class ArraysOfSort {
    public static void main(String[] args) {
        Integer[] data = {5, 3, 6, 1, 8};

        System.out.println(Arrays.toString(data));

        // 采用升序策略
        Arrays.sort(data, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1 - o2;
            }
        });

        System.out.println(Arrays.toString(data));

        // 采用降序策略
        Arrays.sort(data, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });
        System.out.println(Arrays.toString(data));
    }
}
[5, 3, 6, 1, 8]
[1, 3, 5, 6, 8]
[8, 6, 5, 3, 1]

Arrays.sort()源码

 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);
        }
    }

七、策略模式总结

  • 策略模式的关键是:分析项目中变化部分与不变部分
  • 核心思想是:多用组合、聚合,少用继承;用行为类组合,而不是行为的继承,这样更有弹性。
  • 体现了“对修改关闭,对扩展开放的原则”,客户端增加行为不需要修改原有代码,只需要添加一种策略即可,避免了使用if else if else…语句
  • 提供了可以替换继承关系的办法:策略模式将算法封装在独立的strategy类中,使得独立于context改变它,易于切换、理解、扩展
  • 注意:每添加一个策略就要增加一个类,当策略过多时,会导致类的数目庞大
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值