设计模式——行为型模式——策略模式(含实际业务使用示例、可拷贝直接运行)

news2024/11/17 23:35:28

目录

策略模式

定义

组成和UML图

代码示例

实际业务场景下策略模式的使用

策略模式优缺点

使用场景

JDK中使用策略模式示例

参考文档

策略模式

定义

        策略模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。

        策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。

        考虑如下场景:去旅游选择出行方式时,可以骑自行车、坐汽车、坐火车、坐飞机,在不考虑使用策略模式的时候使用if elseif else语句进行判断,此时代码中存在大量条件判断语句,代码不便于增强,不符合开闭原则。将其修改为策略模式可以去掉代码中大量的if判断语句,同时增强代码的可扩展性。

组成和UML图

策略模式的组成

  • 抽象策略(Strategy)类:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。

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

  • 环境(Context)类:持有一个策略类的引用,最终给客户端调用。

策略模式的UML图

代码示例

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

        代码实现:以下示例代码仅仅是一个示例,便于理解策略模式,根据我的实习经验具体公司代码中策略模式不会这样使用的。【最近时间太紧,后期会梳理一下在实习中碰到的公司代码使用策略模式的例子,并更新以下代码示例(2024-05-08已更新,见下文)】

package com.scut.adapter.strategy;

// 定义抽象策略类
public interface Strategy {
    void show();
}

package com.scut.adapter.strategy;
// 策略实现类A
public class StrategyA implements Strategy{
    @Override
    public void show() {
        System.out.println("中秋节活动,赠送中秋大礼包...");
    }
}

package com.scut.adapter.strategy;

// 策略实现类B
public class StrategyB implements Strategy{
    @Override
    public void show() {
        System.out.println("充值一百,送二百...");
    }
}

package com.scut.adapter.strategy;

// 策略实现类C
public class StrategyC implements Strategy{
    @Override
    public void show() {
        System.out.println("圣诞节活动,赠送水果大礼盒一套...");
    }
}

package com.scut.adapter.strategy;

// 定义售卖员,策略上下文类
public class SaleMan {
    private Strategy strategy;

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

    public Strategy getStrategy() {
        return strategy;
    }

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

package com.scut.adapter.strategy;

// 定义客户端、测试类
public class Client {
    public static void main(String[] args) {
        SaleMan saleMan = new SaleMan(new StrategyA());
        saleMan.saleShow();
        System.out.println("====================");
        saleMan.setStrategy(new StrategyB());
        saleMan.saleShow();
        System.out.println("====================");
    }
}
实际业务场景下策略模式的使用

        前置说明:公司中策略模式的使用不会按照以上代码示例的方式使用,更多是结合@Autowire注解注入一系列接口实现类构成一个List集合,进而遍历List集合中的实现类选择具体方法。如下:

        模拟业务场景:电商业务通常需要和发票进行交互,发票简单状态包括:开票、改票、退票。将其抽象并结合策略模式进行设计可以有效减少代码中if else条件判断语句的数量并提高代码可读性。

代码结构如下:

具体代码如下:

package com.example.webmodule;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/hello")
public class InvoiceController {

    @Autowired
    private InvoiceService invoiceService;

    @GetMapping("")
    public String testInvoice(int invoiceStatus){
        invoiceService.invoiceTest(invoiceStatus);
        return "OK";
    }
}



package com.example.webmodule;

public interface InvoiceHandle {
    // 实现类选择器
    boolean canHandle(int invoiceStatus);
    // 具体业务实现
    void invoiceProcess();
}


package com.example.webmodule;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@Slf4j
public class InvoiceService {
    @Autowired
    List<InvoiceHandle> invoiceHandleList;

    public void invoiceTest(int invoiceStatus){
        for (InvoiceHandle invoiceHandle : invoiceHandleList) {
            if(invoiceHandle.canHandle(invoiceStatus)){
                invoiceHandle.invoiceProcess();
            }
        }
    }
}



package com.example.webmodule;

public enum InvoiceStatusEnum {
    MAKE_INVOICE(1, "开票"),
    UPDATE_INVOICE(2, "改票"),
    REFUND_INVOICE(3,"退票");
    private int code;
    private String value;
    InvoiceStatusEnum(int code, String value) {
        this.code = code;
        this.value = value;
    }
    public int getCode(){
        return code;
    }
    public String getValue(){
        return value;
    }
    public void setCode(int code){
        this.code = code;
    }
    public void setValue(String value){
        this.value = value;
    }
}


package com.example.webmodule;

import org.springframework.stereotype.Service;

/**
 * 开票
 */
@Service
public class MakeInvoiceImpl implements InvoiceHandle{
    @Override
    public boolean canHandle(int invoiceStatus) {
        return InvoiceStatusEnum.MAKE_INVOICE.getCode() == invoiceStatus;
    }

    @Override
    public void invoiceProcess() {
        System.out.println("正在开票...");
    }
}


package com.example.webmodule;

import org.springframework.stereotype.Service;

/**
 * 退票
 */
@Service
public class RefundInvoiceImpl implements InvoiceHandle{
    @Override
    public boolean canHandle(int invoiceStatus) {
        return InvoiceStatusEnum.REFUND_INVOICE.getCode() == invoiceStatus;
    }

    @Override
    public void invoiceProcess() {
        System.out.println("正在退票...");
    }
}



package com.example.webmodule;

import org.springframework.stereotype.Service;

/**
 * 改票
 */
@Service
public class UpdateInvoiceImpl implements InvoiceHandle{
    @Override
    public boolean canHandle(int invoiceStatus) {
        return InvoiceStatusEnum.UPDATE_INVOICE.getCode() == invoiceStatus;
    }

    @Override
    public void invoiceProcess() {
        System.out.println("正在改票...");
    }
}

代码演示效果如下:

策略模式优缺点

优点:

  • 策略类之间可以自由切换

    由于策略类都实现同一个接口,所以使它们之间可以自由切换。

  • 易于扩展

    增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码,符合“开闭原则“

  • 避免使用多重条件选择语句(if else),充分体现面向对象设计思想。

缺点:

  • 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。

  • 策略模式将造成产生很多策略类,可以通过使用享元模式在一定程度上减少对象的数量。

使用场景
  • 一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中。

  • 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,可将每个条件分支移入它们各自的策略类中以代替这些条件语句。

  • 系统中各算法彼此完全独立,且要求对客户隐藏具体算法的实现细节时。

  • 系统要求使用算法的客户不应该知道其操作的数据时,可使用策略模式来隐藏与算法相关的数据结构。

  • 多个类只区别在表现行为不同,可以使用策略模式,在运行时动态选择具体要执行的行为。

JDK中使用策略模式示例

        在Arrays类中的 sort() 方法中的Comparator使用的就是策略模式,具体源码可以自行查找以下。

参考文档

策略模式介绍及其具体使用场景_策略模式应用场景-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1665096.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PC端与bluetooth蓝牙虚拟串口通信

应该采用RFCOMM虚拟串口方式来进行通信&#xff0c;原理跟socket通信类似&#xff0c;不同的是使用的通信协议不同&#xff0c;本人结合相关的API&#xff0c;做了以下最简单的封装。 1、获取本地蓝牙设备与附近蓝牙设备信息 2、通信类 /* 通信类&#xff1a;只是对于客户端通…

Live800:企业营销利用利用社区建设培养忠诚粉丝

社区建设是一种与顾客建立长期关系的活动&#xff0c;在社区中顾客可以在有限的时间和空间里&#xff0c;与企业的营销人员进行互动。通过企业提供的各种资源&#xff0c;例如产品、服务、促销活动、信息等&#xff0c;吸引顾客参与社区建设。与顾客建立长期关系&#xff0c;从…

【碳化硅】陷阱(traps)对SiC MOSFET阈值电压漂移的影响

这篇文章是关于硅碳化物(SiC)金属氧化物半导体场效应晶体管(MOSFET)的阈值电压漂移问题的研究。文章的主要目的是通过研究不同的陷阱(traps)对阈值电压漂移的影响,来解决SiC MOSFET的可靠性问题。 摘要(Abstract) 文章提出了一种研究方法,用于分析影响SiC MOSFET阈值…

【练习4】

1.两数之和 暴力&#xff1a; class Solution { public:vector<int> twoSum(vector<int>& nums, int target) {int n nums.size();vector<int> res(2, -1); // 初始化结果为-1for (int i 0; i < n; i) {int temp nums[i];for (int j i 1; j <…

vivado Spartan-7 配置存储器器件

下表所示闪存器件支持通过 Vivado 软件对 Spartan -7 器件执行擦除、空白检查、编程和验证等配置操作。 本附录中的表格所列赛灵思系列非易失性存储器将不断保持更新 &#xff0c; 并支持通过 Vivado 软件对其中所列非易失性存储器 进行擦除、空白检查、编程和验证。赛灵…

用python写个控制MicroSIP自动拨号和定时呼叫功能(可用在小型酒店叫醒服务)MicroSIP定时拨号

首先直接上结果吧&#xff0c;MicroSIP 助手&#xff0c;控制MicroSIP自动拨号&#xff0c;定时呼叫的非常实用小工具&#xff01; 在使用MicroSIP 助手之前&#xff0c;我们需要了解MicroSIP是什么&#xff0c;MicroSIP是一个SIP拨号软件&#xff0c;支持注册任意SIP平台实现拨…

独家原创 | BiTCN-BiGRU-CrossAttention融合时空特征的高创新预测模型

往期精彩内容&#xff1a; 时序预测&#xff1a;LSTM、ARIMA、Holt-Winters、SARIMA模型的分析与比较-CSDN博客 风速预测&#xff08;一&#xff09;数据集介绍和预处理-CSDN博客 风速预测&#xff08;二&#xff09;基于Pytorch的EMD-LSTM模型-CSDN博客 风速预测&#xff…

NSS题目练习2

[LitCTF 2023]我Flag呢&#xff1f; 打开题目后查看源码即可发现flag [第五空间 2021]WebFTP 看到提示&#xff0c;首先想到用dirsearch扫描链接&#xff0c;看是否存在git泄露 发现存在git泄露&#xff0c;用githack解决 克隆提示目录为空&#xff0c;说明不正确&#xff0c…

探讨 vs2019 c++ 里函数指针与函数类型在使用上的语法区别

&#xff08;1&#xff09;咱们可以用 decltype &#xff08;&#xff09; 来判断函数的类型。但以这个类型定义有用的可指向已存在函数的变量&#xff0c;却行不通。测试如下&#xff1a; 如果把上面的注释去掉会报错&#xff1a; 所以函数类型只有语法意义。但在使用上没有函…

PermissionError: [Errno 13] Permission denied: ‘xx.xlsx‘的解决办法

我在转换文件的时候遇到这个报错&#xff0c;原因是文件名与已有文件名重复了 解决办法很简单&#xff0c;如下图把" " 里的名字换成不重复的&#xff0c;再次允许代码&#xff0c;会恢复正常

实验室一块GPU都没有?这个云平台直接送4090免费无门槛代金券!

你有没有一些年代久远的老照片&#xff0c;或是网络下载的图片和视频&#xff0c;低分辨率、模糊还有噪点&#xff0c;如果能一键修复成高清就好了&#xff01;现在在AI算法工程师圈子里很火的GpuMall智算云&#xff0c;上面的镜像可以一键帮你修复照片&#xff01;比如我们用R…

到东莞樟木头“中国作家第一村”来!这里大有文“樟”

樟木头&#xff0c;古称泰安&#xff0c;一直是康泰平安、物阜民丰之地。作为东莞唯一纯客家镇&#xff0c;传自中原先民的烂漫因子让这座城市崇文重礼&#xff0c;绿水青山更氤氲出古镇芳华。这个文章锦绣地&#xff0c;以其敢为人先、勇立潮头的姿态&#xff0c;成为了各种文…

【深度学习】--slowfast视频理解数据集处理pipeline

官网指引&#xff1a; facebookresearch SlowFast &#xff1a;https://github.com/facebookresearch/SlowFast 进入dataset&#xff1a;https://github.com/facebookresearch/SlowFast/blob/main/slowfast/datasets/DATASET.md 这里面的东西需要通读&#xff0c;但是不要过于…

vulnhub靶场之FunBox-5

一.环境搭建 1.靶场描述 Lets separate the script-kids from script-teenies.Hint: The first impression is not always the right one!If you need hints, call me on twitter: 0815R2d2 Have fun...This works better with VirtualBox rather than VMwareThis works bett…

git 推送github 选https遇到登录 openSSH问题

使用https需要使用github令牌token作为密码&#xff0c; 使用SSH不需要登录。 还有一个问题&#xff1a; 创建github仓库后没有quick setup页面解决办法 千万不要点击任何多的操作&#xff01;&#xff01;&#xff01;输入仓库名&#xff0c;直接create&#xff01;&#x…

基于CCS5.5的双音多频(DTMF)信号检测仿真实验(①检测型音频文件②输入生成音频并检测)

DTMF的优点 我们知道,DTMF根本上仍然是频谱分析,基础还是DFT,但DFT通常需要对一整段数据做变换,而DTMF不同,每输入一个采样点就计算一次,更有利于硬件实现。 基于CCS的双音多频(DTMF)信号检测原理 公式详细推导 详细的公式推导在下面这篇博客中已经进行了详细的描述,…

现场工程师出手--虚拟化软件预留内存过大导致其他程序崩溃问题

项目场景&#xff1a; 一位学生有一台笔记本电脑&#xff0c;安装了Android&#xff0c;Kafka虚拟机很多软件。笔记本配置了20GB内存&#xff0c;固态硬盘&#xff0c;但最近很卡&#xff0c;Android Stuido经常闪退&#xff0c;一些游戏也无法运行。 问题描述 由于Android S…

共用nacos造成的开发问题记录

目录 1.需求提出 2.系统架构 3.问题抛出 4.解决办法 1.配置私有命名空间 2.给服务加后缀 1.需求提出 本地调试用到哪个服务启动哪个服务&#xff0c;其他支持服务调用测试环境上的&#xff0c;目的是避免本地启动多个服务&#xff0c;消耗电脑配置。 2.系统架构 项目是…

共绘财富管理新蓝图,ATFX赞助出席拉美峰会,引领家族资本新航向

全球新兴市场中&#xff0c;拉丁美洲以其非凡活力与潜力格外引人注目&#xff0c;成为全球资本竞相追逐的价值洼地。ATFX自2019年开设墨西哥办事处以来&#xff0c;持续深耕拉美市场已成为头部品牌。自4月行业资深人士Ergin Erdemir掌舵拉美业务后&#xff0c;掀起市场营销新浪…

数据库调优-连接池优化

先贴下连接池的相关配置&#xff1a; 连接池参数配置&#xff1a; 字段含义Max Number of Connections最大连接数&#xff1b;做性能测试时&#xff0c;可以填 0 。在开发的项目中按实际代码填写&#xff0c;默认是 20 。Max Wait(ms)在连接池中取回连接最大等待时间&#xf…