第十七章 策略模式

news2024/11/22 20:08:15

目录

1 策略模式概述

2 策略模式原理

 3 策略模式实现

4 策略模式应用实例

5 策略模式总结


1 策略模式概述

策略模式(strategy pattern)的原始定义是:定义一系列算法,将每一个算法封装起来,并使它们可以相互替换。策略模式让算法可以独立于使用它的客户端而变化。

2 策略模式原理

 策略模式的主要角色如下:

  • 抽象策略(Strategy)类:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
  • 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现或行为。
  • 环境或上下文(Context)类:是使用算法的角色, 持有一个策略类的引用,最终给客户端调用。

 3 策略模式实现

/**
 * 抽象策略类
 * @author spikeCong
 * @date 2022/10/13
 **/
public interface Strategy {

    void algorithm();
}

public class ConcreteStrategyA implements Strategy {

    @Override
    public void algorithm() {
        System.out.println("执行策略A");
    }
}

public class ConcreteStrategyB implements Strategy {

    @Override
    public void algorithm() {
        System.out.println("执行策略B");
    }
}

/**
 * 环境类
 * @author spikeCong
 * @date 2022/10/13
 **/
public class Context {

    //维持一个对抽象策略类的引用
    private Strategy strategy;

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

    //调用策略类中的算法
    public void algorithm(){
        strategy.algorithm();
    }
}

public class Client {

    public static void main(String[] args) {


        Strategy strategyA  = new ConcreteStrategyA();
        Context context = new Context(strategyA); //可以在运行时指定类型,通过配置文件+反射机制实现
        context.algorithm();
    }
}

4 策略模式应用实例

1 ) 不使用设计模式

  • 回执类
/**
 * 回执信息
 * @author spikeCong
 * @date 2022/10/13
 **/
public class Receipt {

    private String message; //回执信息

    private String type; //回执类型(MT1101、MT2101、MT4101、MT8104)

    public Receipt() {
    }

    public Receipt(String message, String type) {
        this.message = message;
        this.type = type;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
}
  • 回执生成器
public class ReceiptBuilder {

    public static List<Receipt> genReceiptList(){
        //模拟回执信息
        List<Receipt> receiptList = new ArrayList<>();
        receiptList.add(new Receipt("MT1101回执","MT1011"));
        receiptList.add(new Receipt("MT2101回执","MT2101"));
        receiptList.add(new Receipt("MT4101回执","MT4101"));
        receiptList.add(new Receipt("MT8104回执","MT8104"));

        //......
        return receiptList;
    }

}
  • 客户端
public class Client {

    public static void main(String[] args) {

        List<Receipt> receiptList = ReceiptBuilder.genReceiptList();

        //循环判断
        for (Receipt receipt : receiptList) {
            if("MT1011".equals(receipt.getType())){
                System.out.println("接收到MT1011回执!");
                System.out.println("解析回执内容");
                System.out.println("执行业务逻辑A"+"\n");
            }else if("MT2101".equals(receipt.getType())){
                System.out.println("接收到MT2101回执!");
                System.out.println("解析回执内容");
                System.out.println("执行业务逻辑B"+"\n");
            }else if("MT4101".equals(receipt.getType())) {
                System.out.println("接收到MT4101回执!");
                System.out.println("解析回执内容");
                System.out.println("执行业务逻辑C"+"\n");
            }else if("MT8104".equals(receipt.getType())) {
                System.out.println("接收到MT8104回执!");
                System.out.println("解析回执内容");
                System.out.println("执行业务逻辑D");
            }

            //......
        }
    }
}

2 ) 使用策略模式进行优化

  • 策略接口
/**
 * 回执处理策略接口
 * @author spikeCong
 * @date 2022/10/13
 **/
public interface ReceiptHandleStrategy {

    void handleReceipt(Receipt receipt);
}
  • 具体策略类
public class Mt1011ReceiptHandleStrategy implements ReceiptHandleStrategy {

    @Override
    public void handleReceipt(Receipt receipt) {
        System.out.println("解析报文MT1011: " + receipt.getMessage());
    }
}

public class Mt2101ReceiptHandleStrategy implements ReceiptHandleStrategy {

    @Override
    public void handleReceipt(Receipt receipt) {
        System.out.println("解析报文MT2101: " + receipt.getMessage());
    }
}

......
  • 策略上下文类(策略接口的持有者)
/**
 * 上下文类,持有策略接口
 * @author spikeCong
 * @date 2022/10/13
 **/
public class ReceiptStrategyContext {

    private ReceiptHandleStrategy receiptHandleStrategy;

    public void setReceiptHandleStrategy(ReceiptHandleStrategy receiptHandleStrategy) {
        this.receiptHandleStrategy = receiptHandleStrategy;
    }

    //调用策略类中的方法
    public void handleReceipt(Receipt receipt){
        if(receipt != null){
            receiptHandleStrategy.handleReceipt(receipt);
        }
    }
}
  • 策略工厂
public class ReceiptHandleStrategyFactory {

    public ReceiptHandleStrategyFactory() {
    }

    //使用Map集合存储策略信息,彻底消除if...else
    private static Map<String,ReceiptHandleStrategy> strategyMap;

    //初始化具体策略,保存到map集合
    public static void init(){
        strategyMap = new HashMap<>();
        strategyMap.put("MT1011",new Mt1011ReceiptHandleStrategy());
        strategyMap.put("MT2101",new Mt2101ReceiptHandleStrategy());
    }

    //根据回执类型获取对应策略类对象
    public static ReceiptHandleStrategy getReceiptHandleStrategy(String receiptType){
        return strategyMap.get(receiptType);
    }
}
  • 客户端
public class Client {

    public static void main(String[] args) {

        //模拟回执
        List<Receipt> receiptList = ReceiptBuilder.genReceiptList();


        //策略上下文
        ReceiptStrategyContext context = new ReceiptStrategyContext();

        //策略模式将策略的 定义、创建、使用这三部分进行了解耦
        for (Receipt receipt : receiptList) {
            //获取置策略
            ReceiptHandleStrategyFactory.init();
            ReceiptHandleStrategy strategy = ReceiptHandleStrategyFactory.getReceiptHandleStrategy(receipt.getType());
            //设置策略
            context.setReceiptHandleStrategy(strategy);
            //执行策略
            context.handleReceipt(receipt);
        }
    }
}

5 策略模式总结

1) 策略模式优点:

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

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

  • 易于扩展

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

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

2) 策略模式缺点:

  • 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
  • 策略模式将造成产生很多策略类,可以通过使用享元模式在一定程度上减少对象的数量。

3) 策略模式使用场景

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

    策略模式最大的作用在于分离使用算法的逻辑和算法自身实现的逻辑,这样就意味着当我们想要优化算法自身的实现逻辑时就变得非常便捷,一方面可以采用最新的算法实现逻辑,另一方面可以直接弃用旧算法而采用新算法。使用策略模式能够很方便地进行替换。

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

    在实际开发中,有许多算法可以实现某一功能,如查找、排序等,通过 if-else 等条件判断语句来进行选择非常方便。但是这就会带来一个问题:当在这个算法类中封装了大量查找算法时,该类的代码就会变得非常复杂,维护也会突然就变得非常困难。虽然策略模式看上去比较笨重,但实际上在每一次新增策略时都通过新增类来进行隔离,短期虽然不如直接写 if-else 来得效率高,但长期来看,维护单一的简单类耗费的时间其实远远低于维护一个超大的复杂类。

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

    如果我们不希望客户知道复杂的、与算法相关的数据结构,在具体策略类中封装算法与相关数据结构,可以提高算法的保密性与安全性.

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

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

相关文章

2.PyQT6程序入门实例

1.第一个程序HelloWorld实现 # conding:utf8from PyQt6.QtWidgets import QApplication, QWidget, QLabel import sysapp QApplication(sys.argv) # 创建一个应用 print("sys.argv&#xff0c;获取项目路径", sys.argv) # 获取参数 print("app.arguments()&qu…

05-5.3.1_1 二叉树的先中后序遍历

&#x1f44b; Hi, I’m Beast Cheng&#x1f440; I’m interested in photography, hiking, landscape…&#x1f331; I’m currently learning python, javascript, kotlin…&#x1f4eb; How to reach me --> 458290771qq.com 喜欢《数据结构》部分笔记的小伙伴可以订…

vmmare虚拟机没有被分配ip地址问题;NAT模式下一直变化问题

打开任务管理器–>服务–>找到与VM和server相关的服务 发现NAT和DHCP服务被关闭了 尝试启动&#xff0c;报错 尝试一 虚拟网络编辑器点击还原默认设置 尝试二 可以了 ip变化 更改租用时长

【C++】C++入门的杂碎知识点

思维导图大纲&#xff1a; namespac命名空间 什么是namespace命名空间namespace命名空间有什么用 什么是命名空间 namespace命名空间是一种域&#xff0c;它可以将内部的成员隔绝起来。举个例子&#xff0c;我们都知道有全局变量和局部变量&#xff0c;全局变量存在于全局域…

定点数的加减法以及浮点数的表示

加减法运算是计算机中最基本的计算&#xff0c;由于减法可以看成是负值是加法&#xff0c;因此计算机中使用补码表示有符号数之后&#xff0c;可以将减法运算和加法运算合并在一起讨论。 1.补码的加减运算 补码加减运算的规则简单&#xff0c;公式如下(设机器字长为n)&#x…

Spark日志有哪些?

spark.log&#xff1a;记录作业运行日志&#xff0c;包括Spark框架内部日志和用户通过日志接口输出的日志。 executor 启动结束日志&#xff1a; job&#xff0c;stage&#xff0c;task提交结束日志&#xff1a; pmap.log&#xff1a;周期性地截取Driver或Executor的pmap和…

基于SSM+Jsp的列车票务信息管理系统

开发语言&#xff1a;Java框架&#xff1a;ssm技术&#xff1a;JSPJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包…

多设备互通、开箱即用的私有化笔记软件,极空间部署最强备忘录项目『Memos』

多设备互通、开箱即用的私有化笔记软件&#xff0c;极空间部署最强备忘录项目『Memos』 哈喽小伙伴们好&#xff0c;我是Stark-C~ 手机上的备忘录我想绝大多数的小伙伴都会用到&#xff0c;日常用来记录一下生活中的消费开支清单&#xff0c;或者工作中记录一些重要的任务或项…

欧洲杯“球迷狂欢趴”开启,容声带来“健康养鲜”新理念

6月15日&#xff0c;容声冰箱在深圳举行了异彩纷呈的“欧洲杯养鲜补给站 球迷狂欢趴”系列活动。 容声国内营销总经理韩栋现场发布“以品质领先 为健康养鲜”的主题内容&#xff0c;强调容声将以健康养鲜技术产品的升级迭代&#xff0c;满足用户品质生活需求。 作为有着41年发…

【java分布式计算】分布式计算程序设计基础

期末复习 自留 重点只抓考点 目录 基本技术 SOCKETS网络套接字 多线程 数据序列化 Java I/O流 集合容器 范型 内部类、匿名类、Lambda&#xff08;代码&#xff09; 项目构建管理工具 高级技术 注解&#xff08;代码&#xff09; 反射&#xff08;代码&#xff09;…

为什么选择 ABBYY FineReader PDF ?

帮助用户们对PDF文件进行快速的编辑处理&#xff0c;同时也可以快速识别PDF文件里的文字内容&#xff0c;并且可以让用户们进行文本编辑&#xff0c;所以可以有效提升办公效率。 ABBYY-ABBYY Finereader 15 Win-安装包&#xff1a;https://souurl.cn/OY2L3m 高级转换功能 ABBY…

Python酷库之旅-比翼双飞情侣库(10)

目录 一、xlrd库的由来 二、xlrd库优缺点 1、优点 1-1、支持多种Excel文件格式 1-2、高效性 1-3、开源性 1-4、简单易用 1-5、良好的兼容性 2、缺点 2-1、对.xlsx格式支持有限 2-2、功能相对单一 2-3、更新和维护频率低 2-4、依赖外部资源 三、xlrd库的版本说明 …

常见中间件漏洞

IIS IIS是Internet Information Services的缩写&#xff0c;意为互联网信息服务&#xff0c;是由微软公司提供的基于运行Microsoft Windows的互联网基本服务。 IIS目前只适用于 Windows系统&#xff0c;不适用于其他操作系统。 解析漏洞 IIS6.x 该版本 默认会将 *.asp;.jp…

一. 做一个前后端分离的电商项目(技术栈 : springboot+mybatis-plus+vue) 的前期准备

前期准备 ---- 项目创建和配置 一.创建springboot项目二.项目前期准备工作1. 修改springboot和jdk版本号2.Web请求处理(1) 添加web依赖(2) 测试是否能够成功访问(3) 修改端口号(4) 创建数据库 3. 连接数据库(1) 添加依赖(2)配置application.properties文件(3)添加包扫描 Mapper…

【R语言】数据可视化分析和统计检验——线性和线性混合效应模型

R语言数据可视化分析和统计检验 写在前面1、数据读取及分析2、组间均值和标准差统计分析3、图像数据探索3.1 图像绘制&#xff08;查看是否存在极端数据&#xff0c;以及数据分布情况&#xff09;3. 2 数据标准化&#xff08;Z-scores&#xff09;3.3 绘制数据相关性 4、ggplot…

使用 Python 进行测试(4)为什么要测试?测什么?

总结 要知道测试的内容&#xff0c;首先要知道测试的原因。下面是测试的几个主要目的&#xff1a; 避免回归质量管理匹配规格淡化责任让你放心学习测试选中一个框 你为什么要测试&#xff1f; 要决定测试什么、测试多少以及以什么顺序测试&#xff0c;您需要首先弄清楚测试的…

Docker部署Nginx下载站点服务

1、下载镜像 由于docker官方镜像站点被封了&#xff0c;所以我把镜像上传到阿里云镜像仓库了 docker pull registry.cn-hangzhou.aliyuncs.com/qinzt-tools/file-nginx:1.18.02、运行容器实例 运行变量解释&#xff1a; 变量名称默认值解释USERhyadmin访问下载站点的认证用…

Java--Arrays类

1.数组的工具java.util.Arrays 2.由于数组对象本身并没有什么方法可以供我们调用&#xff0c;但API中提供了一个工具类Arrays供我们使用&#xff0c;从而可以对数据对象进行一些基本的操作。 3.查看JDK帮助文档 4.Arrays类中的方法都是static修饰静态的静态方法&…

Java高频面试题整理(几万字)

&#x1f469;&#x1f3fb; 作者&#xff1a;一只IT攻城狮 &#xff0c;关注我不迷路 ❤️《java面试核心知识》突击系列&#xff0c;持续更新… &#x1f490; 面试必知必会学习路线&#xff1a;Java技术栈面试系列SpringCloud项目实战学习路线 &#x1f4dd;再小的收获x365天…

Golang: 依赖注入与wire —— 构建高效模块化应用的秘诀

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…