3分钟看懂设计模式01:策略模式

一、什么是策略模式

定义一些列算法类,将每一个算法封装起来,并让它们可以互相替换。

策略模式让算法独立于使用它的客户而变化,是一种对象行为型模式。

以上是策略模式的一般定义,属于是课本内容。

在没有真正理解策略模式之前并不需要对此定义下过多功夫,读一遍直接进入下一章节。

二、为什么要用策略模式

我们应该知道,所谓的设计模式实际上是一种经过检验的、科学高效的、针对某种场景的最佳编程设计实践

所以要理解某一种设计模式,就必须知道我们什么时候可以用,用之前和用之后到底有什么区别。

练习:

假设现在要设计一个贩卖各类书籍的电子商务网站的购物车系统。

一个最简单的情况就是把所有货品的单价乘上数量,但是实际情况肯定比这要复杂

比如,本网站可能对所有的高级会员提供每本20%的促销折扣;对中级会员提供每本10%的促销折扣;对初级会员没有折扣。

根据描述,折扣是根据以下的几个算法中的一个进行的:

算法一:对初级会员没有折扣。

算法二:对中级会员提供10%的促销折扣。

算法三:对高级会员提供20%的促销折扣。

给出一本图书,如300元,若是高级会员,则输出价格为240元。

pexels-karolina-grabowska-5650026.jpg

针对以上场景,大多数的我们写的代码就是使用的if…else…。

我们先提前揭晓,这种场景下就是我们使用策略模式的最佳时机。

那在我们尝试使用策略模式改进代码之前,我们必须要问:

if…else到底有什么问题?

传统实现方式

public Double calculationPrice(String type, Double originalPrice, int n) {//中级会员计费if (type.equals("intermediateMember")) {return originalPrice * n - originalPrice * 0.1;}//高级会员计费if (type.equals("advancePrimaryMember")) {return originalPrice * n - originalPrice * 0.2;}//普通会员计费return originalPrice;
}

这种编码方式到底差在哪?

大佬告诉我们说:维护性差。

什么叫维护性差?

就是下次你想加个超级黄金vip会员,以及各种后续会员种类,你就要不断往里加if…else…,这就违反了开闭原则

这里又有另外两个问题:

什么是开闭原则?我凭啥要遵守开闭原则?

什么是开闭原则?

开闭原则比较好记忆,顾名思义:

对扩展开放,对修改关闭。

大意就是你想改东西,不要改原代码,而是进行扩展代码。

为什么要遵守开闭原则(以及各种乱七八糟的原则)?

简单直接一点就是,这些原则都是巨佬们总结出来的,你如果不懂,你就直接选择相信就好了。

解释一下就是:

系统随着开发的不断进展,需求不断增多,代码越来越长,如果没有合理框架的制约那就只能沦为一个扩展难、维护难的屎山。

所以我们遵守开闭原则就是说需要一个科学合理的框架规范我们的系统熵增,在不修改原代码的基础上让系统拥有灵活性和稳定性。

一句话,上面的代码直接修改原代码,时间久了系统只会沦为屎山。

那怎么使用策略模式改造,而遵守开闭原则呢?

策略模式如何实现

Strategy(抽象策略类)

它为所支持的算法声明抽象方法,是所有策略类的父类。它可以使抽象类或者具体类,也可以是接口。

public interface MemberStrategy {// 一个计算价格的抽象方法//price商品的价格 n商品的个数public double calcPrice(double price, int n);
}

ConcreteStrategy(具体策略类)

它实现了上面抽象策略类的抽象方法。

在实际运行中,这个具体的策略类将会代替在**环境类(Context)**中定义的抽象策略类对象最终执行不同的实现逻辑。

可以看到下面的代码中,三种不同的策略类实现了同一个抽象策略类,每种策略对应一种实现,分别应对一个业务处理方式。

// 普通会员——不打折
public class PrimaryMemberStrategy implements MemberStrategy { // 实现策略@Overridepublic double calcPrice(double price, int n) {return price * n;}
}// 中级会员 打百分之10的折扣
public class IntermediateMemberStrategy implements MemberStrategy{@Overridepublic double calcPrice(double price, int n) {double money = (price * n) - price * n * 0.1;return money;}
}// 高级会员类 20%折扣
public class AdvanceMemberStrategy implements MemberStrategy{@Overridepublic double calcPrice(double price, int n) {double money = price * n - price * n * 0.2;return money;}
}

Context(环境类)

这个对我来说一开始很难理解。

主要是不能理解 Context 这个词在这里的意思,再加上网上一大堆直接翻译为“上下文”的文章博客,我直接吐了:

我不理解Context的意思,难道就能理解“上下文”的意思?

还有类似的:事务又是什么东西?

所以我直接不管这个Context是什么东西,直接看代码。

首先他是一个类,我们看这个类里有什么。

一个成员变量memberStrategy

一个构造方法

一个计算价格的方法,内容返回memberStrategy的calcPrice方法

往下看。

/*** 负责和具体的策略类交互* 这样的话,具体的算法和直接的客户端调用分离了,使得算法可以独立于客户端独立的变化。*/// 上下文类/环境类
public class MemberContext {// 用户折扣策略接口private MemberStrategy memberStrategy;// 注入构造方法public MemberContext(MemberStrategy memberStrategy) {this.memberStrategy = memberStrategy;}// 计算价格public double qoutePrice(double goodsPrice, int n){// 通过接口变量调用对应的具体策略return memberStrategy.calcPrice(goodsPrice, n);}}

接下来看测试类中 Context 类的使用是什么样子的。

    // 测试类public class Application {public static void main(String[] args) {// 具体行为策略MemberStrategy primaryMemberStrategy = new PrimaryMemberStrategy(); // 接口回调(向上转型)MemberStrategy intermediateMemberStrategy = new IntermediateMemberStrategy();MemberStrategy advanceMemberStrategy = new AdvanceMemberStrategy();// 用户选择不同策略MemberContext primaryContext = new MemberContext(primaryMemberStrategy);MemberContext intermediateContext = new MemberContext(intermediateMemberStrategy);MemberContext advanceContext = new MemberContext(advanceMemberStrategy);//计算一本300块钱的书System.out.println("普通会员的价格:"+ primaryContext.qoutePrice(300,1));// 普通会员:300System.out.println("中级会员的价格:"+ intermediateContext.qoutePrice(300,1));// 中级会员 270System.out.println("高级会员的价格:"+ advanceContext.qoutePrice(300,1));// 高级会员240}}

发现了什么?

Context都是被new出来的,new的时候传入的Strategy实现类全部不一样,你传的不一样,将来context.calcPrice()执行的逻辑就不一样。

懂了没有?

什么是上下文?

什么是Context?

就是随机应变,像变色龙一样随着不同的环境变化而自由变化。

开发者根据“上下文”不同的业务需求往Context里面放置不同的Strategy。

这就是Context上下文的意思。

这里的Strategy可以你自己new,你也可以把它放在配置类里面配置,然后在代码中读取,这样更加灵活方便。

三、使用策略模式的场景总结

那我们知道了策略模式怎么实现,也就是已经有了一把锤子在手上了,那什么时候用这把锤子呢?

1. 系统中需要动态地在几种算法中选择一种。

2. 一个对象有很多的行为,如果不用策略模式就只能用一大堆的if…else…来实现。

3. 不希望客户端知道复杂的、与算法相关的数据结构。在具体策略类中封装算法和相关的数据结构,提高算法的保密性与安全性。

然后我们用一些实际的例子来理解策略模式的大概的使用场景:

1. 支付方式选择: 假设平台支持多种支付方式,比如微信、支付宝、银行卡等。

2. 数据渲染方式: 如果你有一个应用程序,它可以以多种格式输出数据,比如XML、JSON或CSV。

3. 导航策略: 导航应用多种路径计算方法,如最快路线、最短路线、避开收费路线等。

4. 压缩数据: 根据不同的情况(比如压缩率、速度等)使用不同的压缩算法(如ZIP、RAR、7z等)。

四、策略模式有什么好处

1. 完美支持了开闭原则。

2. 通过抽象算法和继承实现,避免了大量重复代码。

3. 避免了多重选择语句(硬编码,不易维护)。


往期推荐:

● 师爷,翻译翻译什么叫AOP

● 翻译,师爷师爷什么叫事务

● 纪念JDBC

● SpringBoot实现动态数据源配置‍

● 聚簇索引、回表与覆盖索引

● Java锁到底是个什么东西

图片

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

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

相关文章

简单几步通过DD工具把云服务器系统Linux改为windows

简单几部通过DD安装其他系统,当服务器的web控制台没有我们要装的系统,就需要通过DD(Linux磁盘)工具来更改系统,(已知支持KVM系统) 本文如何简单的更换系统,不通过web控制台来更换&a…

Hive【内部表、外部表、临时表、分区表、分桶表】【总结】

目录 Hive的物种表结构特性 一、内部表 建表 使用场景 二、外部表 建表:关键词【EXTERNAL】 场景: 外部表与内部表可互相转换 三、临时表 建表 临时表横向对比​编辑 四、分区表 建表:关键字【PARTITIONED BY】 场景: 五、分桶表 …

算能RISC-V通用云开发空间编译pytorch @openKylin留档

终于可以体验下risc-v了! 操作系统是openKylin,算能的云空间 尝试编译安装pytorch 首先安装git apt install git 然后下载pytorch和算能cpu的库: git clone https://github.com/sophgo/cpuinfo.git git clone https://github.com/pytorc…

小米14 Ultra:未来科技的集大成者

博主猫头虎的技术世界 🌟 欢迎来到猫头虎的博客 — 探索技术的无限可能! 专栏链接: 🔗 精选专栏: 《面试题大全》 — 面试准备的宝典!《IDEA开发秘籍》 — 提升你的IDEA技能!《100天精通鸿蒙》 …

opencv图像的本质

目的 OpenCV是一个跨平台的库,使用它我们可以开发实时的计算机视觉应用程序。 它主要集中在图像处理,视频采集和分析,包括人脸检测和物体检测等功能。 数字图像在计算机中是以矩阵形式存储的,矩阵中的每一个元素都描述一定的图像…

VSCode React JavaScript Snippets 插件的安装与使用指南

VSCode React JavaScript Snippets 插件的安装与使用指南 在开发 React 项目时,提高效率是每个开发者都追求的目标之一。VSCode React JavaScript Snippets 插件就是为了提升 React 开发效率而设计的,它为常用的 React 代码片段提供了快捷键,…

NXP实战笔记(六):S32K3xx基于RTD-SDK在S32DS上配置PWM发波

目录 1、概述 2、SDK配置 2.1、Port配置 2.2、Emios_Mcl_Ip 2.3、Emios_Pwm 2.4、代码示例 1、概述 针对S32K3xx芯片,产生PWM的硬件支持单元仅有两个,分别是eMiosx与Flexio. 生成PWM的顺序,按照单片机所用资源进行初始化执行如下 初始化…

原型模式(Prototype Pattern) C++

上一节:建造者模式(Builder Pattern)C 文章目录 0.理论1.原型模式的核心组成:2.实现方法3.什么时候使用 1.实践步骤 1: 定义怪物原型步骤 2: 实现具体怪物原型步骤 3: 使用原型创建怪物 0.理论 原型模式(Prototype P…

7-liunx服务器规范

目录 概况liunx日志liunx系统日志syslog函数openlog 可以改变syslog默认输出方式 ,进一步结构化 用户信息进程间的关系会话ps命令查看进程关系 系统资源限制改变工作目录和根目录服务器程序后台话 概况 liunx服务器上有很多细节需要注意 ,这些细节很重要…

服务网格Service Mesh和Istio

文章目录 服务网格(Service Mesh)市场上三种服务网格解决方案服务网格的特征流量管理安全性可观察性 Istio简介Istio提供了什么功能服务 ?Istio 核心特性流量管理安全可观察性 平台支持 服务网格(Service Mesh) 服务网…

Eureka注册中心(黑马学习笔记)

Eureka注册中心 假如我们的服务提供者user-service部署了多个实例,如图: 大家思考几个问题: order-service在发起远程调用的时候,该如何得知user-service实例的ip地址和端口? 有多个user-service实例地址&#xff0c…

TreeData 数据查找

TreeData 数据查找 最近做需求的时候遇到了这样的一个需求,Tree组件数据支持查找,而且TreeData的数据层级是无限级的 开始想的事借助UI组件库(Ant-design-vue)中的Tree组件的相关方法直接实现,看了下api 发现没法实现,…

超级实用的python代码片段汇总和详细解析(16个)

目录 1. 生成随机文本 2. 计算文本文件中的字数 3. 替换文件文件中的字串 4. 多文件名的批量替换 5. 从网站提取数据 6. 批量下载图片 7.批量删除空文件夹 8.Excel表格读写 9.合并Excel表格工作簿 10.数据库SQL查询 11. 系统进程查杀 12.图像尺寸调整和裁剪 13.图…

redis实现消息队列redis发布订阅redis监听key

文章目录 Redis消息队列实现异步秒杀1. jvm阻塞队列问题2. 什么是消息队列3. Redis实现消息队列1. 基于List结构模拟消息队列操作优缺点 2. 基于PubSub发布订阅的消息队列操作优缺点spring 结合redis的pubsub使用示例1. 引入依赖2. 配置文件3. RedisConfig4. CustomizeMessageL…

大语言模型的开山之作—探秘GPT系列:GPT-1-GPT2-GPT-3的进化之路

模型模型参数创新点评价GPT1预训练微调, 创新点在于Task-specific input transformations。GPT215亿参数预训练PromptPredict, 创新点在于Zero-shotZero-shot新颖度拉满,但模型性能拉胯GPT31750亿参数预训练PromptPredict, 创新点…

pclpy 可视化点云(多窗口可视化、单窗口多点云可视化)

pclpy 可视化点云(多窗口可视化、单窗口多点云可视化) 一、算法原理二、代码三、结果1.多窗口可视化结果2.单窗口多点云可视化 四、相关数据五、问题与解决方案1.问题2.解决 一、算法原理 原理看一下代码写的很仔细的。。目前在同一个窗口最多建立2个窗…

ESP8266智能家居(3)——单片机数据发送到mqtt服务器

1.主要思想 前期已学习如何用ESP8266连接WIFI,并发送数据到服务器。现在只需要在单片机与nodeMCU之间建立起串口通信,这样单片机就可以将传感器测到的数据:光照,温度,湿度等等传递给8266了,然后8266再对数据…

【AI应用】SoraWebui——在线文生视频工具

SoraWebui 是一个开源项目,允许用户使用 OpenAI 的 Sora 模型使用文本在线生成视频,从而简化视频创建,并具有轻松的一键网站部署功能 在 Vercel 上部署 1. 克隆项目 git clone gitgithub.com:SoraWebui/SoraWebui.git 2. 安装依赖 cd Sor…

【Java EE初阶二十】http的简单理解(一)

1. 初识http HTTP 最新的版本应该是 HTTP/3.0,目前大规模使用的版本 HTTP/1.1; 下面来简单说明一下使用 HTTP 协议的场景: 1、浏览器打开网站 (基本上) 2、手机 APP 访问对应的服务器 (大概率) 前面的 TCP与UDP 和http不同,HTTP 的报文格式&a…

React基础-webpack+creact-react-app创建项目

学习视频:学习视频 2节:webpack工程化创建项目 2.1.webpack工程化工具:vite/rollup/turbopak; 实现组件的合并、压缩、打包等; 代码编译、兼容、校验等; 2.2.React工程化/组件开发 我们可以基于webpack自己去搭建…