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

news/2025/2/25 13:26:48

一、概述

策略模式(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. 禁止未经授权的商业转载。

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


http://www.niftyadmin.cn/n/5865548.html

相关文章

一天记20个忘10个之4:man

据说,给你一个支点,你就能撬起地球。 那好,今天,我给你一个 man,如果你能完成记20个忘10个的任务,你就真的很 man 了。 零、热身 young manold manmedical man 一、man之复合词 1.1 man复合词 chairm…

Pytorch实现论文:基于多尺度融合生成对抗网络的水下图像增强

简介 简介:提出了一种新型的水下图像增强算法,基于多尺度融合生成对抗网络,名为UMSGAN,以解决低对比度和颜色失真的问题。首先经过亮度的处理,将处理后的图像输入设计的MFFEM模块和RM模块生成图像。该算法旨在适应各种水下场景,提供颜色校正和细节增强。 论文题目:Und…

【Java毕业设计】商城购物系统(附源码+数据库脚本)

本系统是基于JavaEEServletJSPMysql实现的商城购物系统。包括用户登录、用户注册、商品分类、添加购物车、订单支付等基本功能,具体页面及功能如下: 感谢阅读! 如需获取完整项目源码及更多项目信息,可添加V:

Day 49 卡玛笔记

这是基于代码随想录的每日打卡 1143. 最长公共子序列 给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变…

MQ(Message Queue)

目录 MQ(Message Queue)基本概念 为什么要使用消息队列? 使用消息队列有什么缺点? 如何保证消息不丢失?(如何保证消息的可靠性传输?/如何处理消息丢失的问题?) 通用的MQ场景: RabbitMQ如何保证消息不丢失? 生产者丢数据…

QVariantList使用详解

QVariantList 1. 基本概念2. 使用场景3. 基本操作3.1 创建和初始化3.2 访问元素3.3 修改元素3.4 删除元素 4. 实际应用示例5. 总结其他QT文章推荐 QVariantList 是 Qt 框架中的一个类,用于存储和操作 QVariant 对象的列表。 QVariant 是 Qt 中用于封装各种类型的通…

4. MySQL 逻辑架构说明

4. MySQL 逻辑架构说明 文章目录 4. MySQL 逻辑架构说明1. 逻辑架构剖析1.1 服务器处理客户端请求1.2 Connectors(连接器)1.3 第1层:连接层1.4 第2层:服务层1.5 第3层:引擎层1.6 存储层 2. SQL执行流程2.1 MySQL 中的 SQL 执行流程 2.2 MySQL…

Web前端开发——HTML基础

本系列博客声明,根据本人所学书籍和网上的一些资料共同磨合,写下web前端系列的博客 HTML基础 一、HTML基本概述[^1]二、HTML大体认知1.HTML基本结构2.HTML 语法格式 三、THML常用标记[^2]1.文本标记(1)标题(2&#xf…