icode icode
首页
  • Android学习

    • 📁基础内容
    • 📺AndroidCore
    • 🎨Android-UI
    • 🏖️Components
    • 📊Fragment
    • 🔗网络操作
    • 🔏异步机制
    • 📦数据存储
    • 🗃️Gradle
  • 学习笔记

    • 『框架』笔记
    • 『Kotlin』笔记
    • 《Vue》笔记
    • 《Git》学习笔记
    • 『Bug踩坑记录』
  • ListView
  • RecyclerView
  • ViewPager
  • Java笔记

    • 🟠JavaSE
    • 🟢JavaWeb
    • 🔴JavaEE
    • ⚪JavaTopic
    • 🍳设计模式
  • 计算机基础

    • 📌计算机网络
    • 🔍数据结构
    • 📦数据库
    • 💻OS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 关于

    • 📫关于我
  • 收藏

    • 网站
    • 资源
    • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

iqqcode

保持对技术的探索实践与热爱
首页
  • Android学习

    • 📁基础内容
    • 📺AndroidCore
    • 🎨Android-UI
    • 🏖️Components
    • 📊Fragment
    • 🔗网络操作
    • 🔏异步机制
    • 📦数据存储
    • 🗃️Gradle
  • 学习笔记

    • 『框架』笔记
    • 『Kotlin』笔记
    • 《Vue》笔记
    • 《Git》学习笔记
    • 『Bug踩坑记录』
  • ListView
  • RecyclerView
  • ViewPager
  • Java笔记

    • 🟠JavaSE
    • 🟢JavaWeb
    • 🔴JavaEE
    • ⚪JavaTopic
    • 🍳设计模式
  • 计算机基础

    • 📌计算机网络
    • 🔍数据结构
    • 📦数据库
    • 💻OS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 关于

    • 📫关于我
  • 收藏

    • 网站
    • 资源
    • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • JavaSE

  • JavaWeb

  • JavaEE

  • JavaTopic

  • 设计模式

    • 单例模式
    • 单例模式应用场景
    • 策略模式
      • 策略模式
      • 案例实现
      • 策略模式优缺点
      • 使用场景
      • JDK中的策略模式应用
  • 计算机基础

  • Java后端
  • 设计模式
iqqcode
2021-06-17
目录

策略模式

# 策略模式

定义:

该模式定义了一系列算法,并将每个算法封装起来;它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,他通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。

结构:

  • 抽象策略类「Strategy」:这是一个抽象角色,通常由一个接口或抽象类实现。此角色会给出说有的具体策略类所需的接口(抽取出抽象方法,起到规定的作用)

  • 具体策略类「Concrete Strategy」:实现了抽象策略定义的接口,提供具体的算法实现或行为

  • 环境类「Context」:出游一个策略类的引用,做种给客户端调用

策略模式其实就是在代码结构上调整,用接口+实现类+分派逻辑来使代码结构可维护性更好。


# 案例实现

【例子】促销活动

一家百货公司在定年度的促销活动。针对不同的节日(春节、中秋节、圣诞节)推出不同的促销活动,由促销员将促销活动展示给客户。

类图如下:

  • Stretegy-抽象策略类:展示促销活动的内容

  • StretegyA~C-具体策略类:实现促销接口,负责展示该促销活动的内容

  • StretegyMan(销售员)-环境类:促销员为客户展示促销内容

Strategy接口

抽象策略类-提供接口, 促销活动接口

public interface Strategy {
    void show();
}
1
2
3

StrategyA

具体策略类,封装算法;实现促销接口,负责展示该促销活动的内容

public class StrategyA implements Strategy {
    @Override
    public void show() {
        System.out.println("买一送一");
    }
}
1
2
3
4
5
6
public class StrategyB implements Strategy {
    @Override
    public void show() {
        System.out.println("满200减50!");
    }
}
1
2
3
4
5
6
public class StrategyC implements Strategy {
    @Override
    public void show() {
        System.out.println("满1000打8折...");
    }
}
1
2
3
4
5
6

SalesMan

环境类-聚合策略类;促销员

public class SalesMan {
    // 聚合策略类
    private Strategy strategy;

    public SalesMan(Strategy strategy) {
        this.strategy = strategy;
    }

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    // 出校源展示促销活动给用户
    public void salesManStrategy() {
        strategy.show();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

Usre用户测试类

public class Usre {
    public static void main(String[] args) {
        // 春节促销活动
        SalesMan salesMan = new SalesMan(new StrategyA());
        // 展示促销活动
        System.out.print("春节促销活动!");
        salesMan.salesManStrategy();


        // 中秋促销活动
        System.out.print("中秋促销活动!");
        salesMan.setStrategy(new StrategyB());
        salesMan.salesManStrategy();


        // 元旦促销活动

        System.out.print("元旦促销活动!");
        salesMan.setStrategy(new StrategyC());
        salesMan.salesManStrategy();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 策略模式优缺点

【优点】

  • 易于拓展 增加一个新的策略只需要添加一个具体的策略即可,符合开闭原则

  • 策略类之间可以自由切换 策略类都实现同一个接口,可以自由切换

  • 优化多重条件选择语句 体现面向对象的设计思想

【缺点】

  • 客户端必须知道所有的策略类,从而决定具体使用哪一个类

  • 容易造成有很多策略类,可以通过<享元模式>在一定程度上减少对象数量


# 使用场景

  1. 一个系统需要动态的选择几种算法时,可以将每个算法的实现分装到策略类中;
  2. 一个类定义多种行为,可以将这个类的条件分支语句移入各自的策略类中代替条件语句
  3. 各算法完全独立,对客户隐藏具体算法实现的细节

# JDK中的策略模式应用

Comparator 中的策略模式。在Arrays类种有sort方法如下:

public static <T> void sort(T[] a, int fromIndex, int toIndex,
                            Comparator<? super T> c) {
    if (c == null) {
        sort(a, fromIndex, toIndex);
    } else {
        rangeCheck(a.length, fromIndex, toIndex);
        if (LegacyMergeSort.userRequested)
            legacyMergeSort(a, fromIndex, toIndex, c);
        else
            TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

Arrays 就是一个环境角色类,sort方法传入 新策略 (由小到大还是由大到小)让Arrays根据策略进行排序。如下的测试类:

public static void main(String[] args) {
    Integer[] nums = {4, 5, 1, 3, 9, 7, 5};
    Arrays.sort(nums, new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o2 - o1;
        }
    });
    // [9, 7, 5, 5, 4, 3, 1]
}
1
2
3
4
5
6
7
8
9
10

在调用Arrays 类的sort方法时,第二个参数传递的是 Comparator 接口的实现类对象。

  • Comparator 充当的是抽象策略角色

  • 具体的实现类充当的是具体策略角色

  • Arrays 类充当环境角色类,持有抽象策略的引用来调用


Arrays 类的sort方法到底有没有使用 Comparator 子类中的compare() 方法呢?在TimSort 类的sort方法如下:

private static <T> int countRunAndMakeAscending(T[] a, int lo, int hi,
                                                Comparator<? super T> c) {
    assert lo < hi;
    int runHi = lo + 1;
    if (runHi == hi)
        return 1;
    // Find end of run, and reverse range if descending
    if (c.compare(a[runHi++], a[lo]) < 0) { // Descending
        while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0)
            runHi++;
        reverseRange(a, lo, runHi);
    } else {                              // Ascending
        while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0)
            runHi++;
    }
    return runHi - lo;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

我们可以看到此处调用了c的compare方法,由此得出结论:Arrays 类的sort方法使用了Comparator 子类中的compare() 方法

编辑 (opens new window)
上次更新: 2021/06/27, 10:49:09
单例模式应用场景
📌计算机网络

← 单例模式应用场景 📌计算机网络→

最近更新
01
匿名内部类
10-08
02
函数式接口
10-08
03
ARouter-Kotlin踩坑
10-05
更多文章>
Theme by Vdoing | Copyright © 2021-2023 iqqcode | MIT License | 备案号-京ICP备2021028793号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×