当前位置: 首页 > news >正文

设计模式教程:策略模式(Strategy Pattern)

一、概述

策略模式(Strategy Pattern) 是一种行为型设计模式,旨在定义一系列算法(或行为),并将它们封装到独立的类中,使得它们可以互相替换。策略模式让算法的变化独立于使用算法的客户端,从而解决了传统代码中将不同算法嵌入到同一个类中的问题。通过策略模式,我们可以灵活地选择不同的策略,而不需要修改具体的业务代码。

二、策略模式的结构

策略模式主要包括以下几个角色:

  1. Context(上下文类)

    • 作用:维护一个对策略对象的引用,并根据需要执行策略。上下文类并不关心具体使用哪一种策略,它只负责将策略委托给具体的策略类。
    • 职责:使用策略并与策略交互。
  2. Strategy(策略接口)

    • 作用:定义一个公共接口,所有具体的策略都必须实现这个接口。
    • 职责:声明执行某个操作的算法或行为。
  3. ConcreteStrategy(具体策略类)

    • 作用:实现策略接口中的具体行为。
    • 职责:封装具体的算法或业务逻辑,提供不同的实现方式。

三、策略模式的优缺点

优点:
  1. 避免了大量的条件判断:使用策略模式将不同的算法或行为封装到不同的策略类中,避免了在代码中出现大量的 if-elseswitch-case 判断。
  2. 增加可扩展性:当需要增加新的策略时,只需要新增一个策略类,不需要修改现有的代码,符合开闭原则(对扩展开放,对修改关闭)。
  3. 减少了类的耦合度:策略模式让算法独立于客户端,减少了不同算法之间的依赖性,使得代码更加灵活、易于测试。
缺点:
  1. 增加了类的数量:每增加一个策略就需要增加一个新的策略类,因此在策略较多时,可能会导致类的数量较多,增加代码复杂度。
  2. 客户端必须知道所有策略:虽然策略的使用是灵活的,但客户端必须知道可以使用哪些策略,可能会使得客户端代码变得稍显复杂。

四、策略模式的应用场景

策略模式适用于以下几种情况:

  1. 算法的选择:如果某个类的行为表现为多种不同的算法,且这些算法之间可以互换,策略模式非常适合。
  2. 避免条件语句:当一个类的行为依赖于多个条件语句来选择不同的算法时,使用策略模式可以清晰地组织代码,避免过多的条件判断。
  3. 系统中的策略经常变化:当系统中的策略在运行时发生变化,且希望能够灵活切换这些策略时,策略模式可以很好地提供解决方案。

五、策略模式的实现

下面我们通过一个例子来展示如何使用策略模式。

1. 定义策略接口

首先,我们需要定义一个 Strategy 接口,它包含一个 execute() 方法,所有的具体策略类都需要实现这个接口。

public interface Strategy {
    void execute();
}
2. 定义具体策略类

然后,我们定义几种具体的策略类,每种策略实现 Strategy 接口,并提供不同的行为。

// 具体策略1:加法策略
public class AddStrategy implements Strategy {
    @Override
    public void execute() {
        System.out.println("执行加法策略");
    }
}

// 具体策略2:减法策略
public class SubtractStrategy implements Strategy {
    @Override
    public void execute() {
        System.out.println("执行减法策略");
    }
}

// 具体策略3:乘法策略
public class MultiplyStrategy implements Strategy {
    @Override
    public void execute() {
        System.out.println("执行乘法策略");
    }
}
3. 定义上下文类

接下来,我们定义一个 Context 类,它包含一个 Strategy 类型的成员变量,并提供一个 setStrategy() 方法来设置策略,最后通过 executeStrategy() 方法来执行策略。

public class Context {
    private Strategy strategy;

    // 设置策略
    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    // 执行策略
    public void executeStrategy() {
        strategy.execute();
    }
}
4. 使用策略模式

Main 方法中,我们创建一个 Context 对象,并在运行时动态地切换不同的策略。

public class Main {
    public static void main(String[] args) {
        // 创建上下文对象
        Context context = new Context();
        
        // 设置加法策略
        context.setStrategy(new AddStrategy());
        context.executeStrategy();  // 输出:执行加法策略
        
        // 设置减法策略
        context.setStrategy(new SubtractStrategy());
        context.executeStrategy();  // 输出:执行减法策略
        
        // 设置乘法策略
        context.setStrategy(new MultiplyStrategy());
        context.executeStrategy();  // 输出:执行乘法策略
    }
}

六、深入分析

在这个例子中,Strategy 接口定义了策略的标准方法,具体的策略类(AddStrategySubtractStrategyMultiplyStrategy)实现了不同的行为。Context 类则是策略模式的核心,它持有一个 Strategy 对象,并提供 setStrategy() 方法来动态切换策略。

为什么使用策略模式?

  • 避免了条件语句:如果没有使用策略模式,我们可能会在 Context 类中使用一系列的 if-elseswitch-case 语句来判断当前选择的策略,而策略模式通过将每种策略封装到独立的类中,避免了这种情况。
  • 提高了可扩展性:当需要新增一种策略时,只需要创建一个新的策略类,并将其传入 Context 类中,无需修改已有的代码。
  • 符合开闭原则:增加新的策略不会影响现有代码的运行,符合对扩展开放,对修改关闭的原则。

七、策略模式与其他设计模式的比较

1. 策略模式 vs 状态模式

策略模式和状态模式有相似之处,都是通过将不同的行为封装到不同的类中来避免条件判断,但它们的应用场景不同:

  • 策略模式:适用于不同的算法或行为可以互换的情况,策略之间通常是独立的。
  • 状态模式:适用于对象的行为依赖于其状态的变化,状态之间存在一定的转换规则。

总结来说,策略模式关注的是 不同算法的选择,而状态模式关注的是 状态变化导致的行为变化

2. 策略模式 vs 模板方法模式
  • 策略模式:将算法封装成独立的策略类,通过上下文类来选择并使用不同的策略。
  • 模板方法模式:在父类中定义算法的骨架,将一些步骤的具体实现延迟到子类中。

策略模式适用于算法的选择和切换,而模板方法模式则适用于算法步骤已经确定,但某些步骤的实现交给子类来完成的场景。

八、总结

策略模式通过将不同的算法或行为封装到独立的策略类中,消除了复杂的条件判断,使得代码更加灵活、易于扩展。它非常适合那些需要在运行时选择不同算法的场景,通过使用策略模式,我们可以轻松地替换算法,避免修改现有代码,提升系统的可维护性。

策略模式的主要优势在于 解耦算法和客户端,使得客户端可以更加灵活地选择不同的策略。然而,随着策略数量的增加,类的数量也会增多,可能导致系统中类的数量过多,因此在使用时需要根据实际情况权衡。

版权声明
  1. 本文内容属于原创,欢迎转载,但请务必注明出处和作者,尊重原创版权。
  2. 转载时,请附带原文链接并注明“本文作者:扣丁梦想家
  3. 禁止未经授权的商业转载。

如果您有任何问题或建议,欢迎留言讨论。

相关文章:

  • C++程序员内功修炼——Linux C/C++编程技术汇总
  • RK3399 Android7 Ethernet Tether功能实现
  • 香港多IP站群服务器
  • 【时时三省】(C语言基础)顺序程序设计举例
  • 【无人集群系列---大疆无人集群技术进展、技术路线与未来发展方向】
  • 汽车零部件工厂如何通过ESD监控系统闸机提升产品质量
  • 如何在 CMake 上设置新项目以获得成功
  • 起猛了,植物大战僵尸出了金铲铲模式?
  • Linux 核心架构与组件(2025更新中)
  • 回溯算法之组合和排列问题
  • B站pwn教程笔记-2
  • 应对LLM应用中的AI幻觉,如何通过Token对数概率预测LLM的可靠性
  • 【新手入门】SQL注入之伪静态注入
  • 英语学习DAY5
  • 2022 年学习 Spring Boot 开发的最佳书籍
  • Mysql 主从集群同步延迟问题怎么解决?
  • Vi 编辑器基本使用指南
  • DeepSeek引领目标检测新趋势:如何通过知识蒸馏优化模型性能
  • DroidDissector本地部署
  • [实现Rpc] 客户端 | Requestor | RpcCaller的设计实现
  • 澎湃与七猫联合启动百万奖金征文,赋能非虚构与现实题材创作
  • 网易一季度净利增长三成,丁磊:高度重视海外游戏市场
  • 现场丨在胡适施蛰存等手札与文献间,再看百年光华
  • 微软宣布全球裁员约3%:涉及约6000人,侧重经理层
  • 中科飞测将投资超10亿元,在上海张江成立第二总部
  • 前四个月社会融资规模增量累计为16.34万亿元,比上年同期多3.61万亿元