策略模式的理解和运用

在之前的小游戏项目中,处理websocket长连接请求的时候,需要根据传递数据包的不同类型,进行不同的处理。为了实现这个场景,比较简单的方法就是使用if-else或者switch-case语句,根据条件进行判断。但是这导致了项目代码复杂混乱,不利用项目后期的维护和扩展。

策略模式和观察者模式都可以解决这个大量条件判断的问题,相比之下,观察者模式比较复杂,适用于更加复杂的场景。而策略模式则比较轻便,简单易上手。

关于观察者模式,感兴趣的朋友可以看这一篇博客:

观察者模式的理解和引用-CSDN博客

旧代码如下

		//在信息中枢处根据消息类型进行特定的处理switch requestPkg.Type {case pojo.CertificationType://用户认证client.CertificationProcess(requestPkg)case pojo.CreateRoomType://创建房间号,并将创建者加入房间client.CreateRoomProcess()case pojo.JoinRoomType://1.加入房间的前提,先建立连接//2.完成用户认证//3.发送消息类型和房间号 Type uuid//只有完成上述步骤,才可以加入房间var data map[string]interface{}err = json.Unmarshal([]byte(requestPkg.Data), &data)if err != nil {fmt.Println("解析 JSON 失败:", err)return}uuidValue, ok := data["uuid"].(string)if !ok {fmt.Println("uuid 字段不存在或不是字符串类型")return}client.JoinRoomProcess(uuidValue)case pojo.RefreshScoreType://什么是否进行分数更新,前端判断 type:RefreshScoreType, data:step、step、score//当用户的行为触发前端游戏机制的更新时,前端调用此接口,后端进行分数的转发 不需要做业务处理,直接转发即可fmt.Println("游戏交换中数据", client)client.RefreshScoreProcess(requestPkg)case pojo.DiscontinueQuitType:client.DiscontinueQuitProcess()case pojo.GameOverType://游戏结束类型好像没有太大用,游戏结束的时候的提醒,通过分数更新就可以实现了fmt.Println("GameOverType")case pojo.HeartCheckType://开启一个协程遍历hub中的Client,进行健康检测,生命时间是否会过期,如果过期进行逻辑删除和关闭连接if requestPkg.Data == "PING" {client.HeartCheckProcess()}}

策略模式介绍

策略模式是一种软件设计模式,它允许在运行时选择算法的行为。策略模式定义了一系列算法,并使它们能够相互替换,从而使算法可以独立于其使用者而变化。这意味着在实际使用中,可以在不修改其结构的情况下轻松地切换或替换算法。在我们的场景下,我们通过websocket连接获取到的数据包有很多的类型:CertificationType、CreateRoomType、JoinRoomType、RefreshScoreType、DiscontinueQuitType、GameOverType、HeartCheckType等类型,我们需要根据不同的类型对数据进行不同的处理。即在运行时,根据传入的Type值,选择不同的行为进行处理,使得我们可以在运行的过程中轻松切换行为。【这里可以将算法理解成对同样结构的输入,进行不同的处理。】

Context上下文对象类:该对象持有对策略接口的引用,可以根据需要动态地改变所使用的具体策略。这样,客户端调用上下文对象的方法时,就可以根据所设置的具体策略来执行相应的算法。

//将Strategy策略作为Context上下文对象的一个字段
//封装get、set、execStrategy(执行方法)
type Context struct {Strategy handler.Strategy 
}func (c *Context) SetStrategy(strategy handler.Strategy) {c.Strategy = strategy
}func (c *Context) GetStrategy() handler.Strategy {return c.Strategy
}func (c *Context) ExecStrategy(client *pojo.Client, request req.WsReq) {c.Strategy.StrategyMethod(client, request)
}

Strategy策略接口:定义接口,接口里面是StrategyMethod()方法,在Context对象的ExecStrategy()方法中被调用。

type Strategy interface {StrategyMethod(client *pojo.Client, request req.WsReq)
}

ConcreteStrategy具体策略类:该类实现Strategy接口,并且根据自身的需要定义StrategyMethod()方法具体的业务代码。

type LifetimeCheck struct {
}func (c *LifetimeCheck) StrategyMethod(client *pojo.Client, req req.WsReq) {if string(req.Data) == `"PING"` {client.User.Lifetime = client.User.Lifetime.Add(10 * time.Second)}wsResp := resp.WsResp{Type: req.Type, Data: "PONG"}if err := wsResp.WsResponseSuccess(client); err != nil {zap.L().Error("PING 返回出现错误")return}
}

客户端代码:创建上下文对象,根据需求,去调用SetStrategy()方法,并执行所设置策略的行为。我们的选择可以通过Map进行,根据map的key获取对应的具体策略对象。

func WsController(client *pojo.Client) {//map初始化之后就没有写入操作了,所以不存在线程安全的问题!!! 只会进行读取操作context := new(Context)//1.执行认证行为context.SetStrategy(new(specificHandler.CertificationStrategy))context.ExecStrategy(client, request)//2.执行心跳检测context.SetStrategy(new(specificHandler.LifetimeCheck))context.ExecStrategy(client, request)//1.执行聊天信息context.SetStrategy(new(specificHandler.ChatStrategy))context.ExecStrategy(client, request)
}

通过这样改造之后,我们的代码就可以实现:

  1. 算法可以独立于客户端而变化,客户端可以更灵活地选择算法。
  2. 可以避免大量的条件语句,将算法的选择和使用分离开来,提高了代码的可维护性和扩展性。
  3. 可以方便地增加、删除或更改算法,不会影响到客户端的代码。

总的来说,策略模式可以帮助我们更好地组织和管理不同的算法,使系统更加灵活、可扩展和易于维护。

策略选择改进

读到这里,大家可以发现,其实还是没有办法解决我们代码里面出现的大量if - else语句,我们需要通过if - else来做判断,帮助我们选择对应的行为。其实,这里可以引入map帮助我们来做选择,如果命中map中的key,就返回对应的算法对象。
代码如下:

func WsController(client *pojo.Client) {//map初始化之后就没有写入操作了,所以不存在线程安全的问题!!! 只会进行读取操作context := new(Context)handlerMap := map[string]handler.Strategy{}//对客户端发送过来的对应请求类型,进行注册操作handlerMap[CertificationType] = new(specificHandler.CertificationStrategy)handlerMap[ChatType] = new(specificHandler.ChatStrategy)handlerMap[CommentNotificationType] = new(specificHandler.CommentNotification)handlerMap[FansNotificationType] = new(specificHandler.FansNotification)handlerMap[CloseType] = new(specificHandler.CloseConnection)handlerMap[LifetimeCheckType] = new(specificHandler.LifetimeCheck)for {request := req.WsReq{}//循环读取对应的类型,并进行反序列化client.Conn.ReadJSON(&request)//通过定义的map,通过对应的数据类型获取算法对象。如果能够获取到更改上下文,并执行匹配到的策略,处理数据if strategy, ok := handlerMap[request.Type]; ok {context.SetStrategy(strategy)context.ExecStrategy(client, request)} else {zap.L().Error("长连接请求类型不存在")}}
}

更改后的代码整体结构:

总结

代码并不是能跑就可以了,如果可以的话,请尽可能地优化自己的代码,让自己的代码利于维护和扩展,可读性高。

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

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

相关文章

AI驱动下,需要重新审视比亚迪在电子制造领域的“新神话”?

自4月22日创下新低后,比亚迪电子(00285.HK)之后趋势走强,截至6月5日收盘,比亚迪电子股价一度突破年内最高价位37.35港元/股,最终收盘36.75港元/股。 区间29个交易日涨超55%,远远优于…

OneDrive空间清理及文件历史版本查询

点击OneDrive图标 点击“在线查看” 点击“设置” 点击“OneDrive设置” 点击“其他设置” 点击“存储标准” 点击“文档” 选择需要操作的文件,点击“历史版本记录” 需要清理空间,可删除历史版本,需要使用历史版本,可还原历史版…

数据报表统计实现

目录 一:背景 二:实现过程 一:背景 最近需要开发一个数据统计的功能,主要是按照各种维度统计客户的数据,一般是按照日期来展示数量和变化情况。下面我们来梳理下实现的过程。 二:实现过程 1&#xff1a…

Postgresql中json和jsonb类型区别

在我们的业务开发中,可能会因为特殊【历史,偷懒,防止表连接】经常会有JSON或者JSONArray类的数据存储到某列中,这个时候再PG数据库中有两种数据格式可以直接一对多或者一对一的映射对象。所以我们也可能会经常用到这类格式数据&am…

港中文斯坦福提出SD加速模型PCM,一步即可生成图像和视频,可直接与SD1.5,SDXL,AnimateLCM结合!

又有新的SD加速模型可以用了,PCM解决了原来LCM模型的各种问题。并且对 AnimateLCM 也做了优化,用PCM直接生成动画也可以保证质量了。 PCM从这三个角度说明了LCM的设计空间是有限的并很好地解决了这些限制。 PCM主要改善了三个LCM原有的问题:…

LeetCode 热题 100 第56.合并区间

思路&#xff1a; class Solution {public int[][] merge(int[][] intervals) {if(intervals.length < 1) return intervals;List<int[]> res new ArrayList<>();Arrays.sort(intervals, (o1,o2) -> o1[0] - o2[0]);for(int[] interval : intervals){if(res…

UML交互图-序列图

概述 序列图又称为时序图、活动序列图&#xff0c;它是一种详细表示对象之间及对象与参与者实例之间交互的图,它由一组协作的对象(或参与者实例)及它们之间可发送的消息组成&#xff0c;它强调消息之间的时间顺序。 序列图主要用于按照交互发生的一系列顺序&#xff0c;显示对…

【Java】static 修饰变量

static 一种java内置关键字&#xff0c;静态关键字&#xff0c;可以修饰成员变量、成员方法。 static 成员变量 1.static 成员变量2.类变量图解3.类变量的访问4.类变量的内存原理5.类变量的应用 1.static 成员变量 成员变量按照有无static修饰&#xff0c;可以分为 类变量…

体验SmartEDA:颠覆传统,设计流程更流畅,超越Multisim与Proteus!

在电子设计自动化&#xff08;EDA&#xff09;领域&#xff0c;传统软件如Multisim和Proteus一直是工程师们的得力助手。然而&#xff0c;随着科技的飞速发展和用户需求的不断升级&#xff0c;一个全新的EDA平台——SmartEDA正崭露头角&#xff0c;凭借其更为流畅的设计流程&am…

使python技能飙升的5个实用F-String技巧

前言 python中存在着一些奇奇怪怪的语法&#xff0c;了解这些语法可以使我们在编写程序时事半功倍&#xff0c;不了解的则会使我们产生疑惑。今天&#xff0c;我们来了解一下python中关于f-string的5个实用的小技巧。 技巧一:数字分隔 num 1000000000 print(-*20)print(f{n…

性能测试中如何设计真实的负载呢?

引言&#xff1a; 性能测试是一项关键的软件开发活动&#xff0c;它可以帮助我们评估系统在不同负载下的响应能力&#xff0c;并找出系统的瓶颈。然而&#xff0c;要确保我们的性能测试结果真实可靠&#xff0c;我们需要设计一个真实的负载。本文将从零开始&#xff0c;详细介…

基于System-Verilog实现DE2-115开发板驱动HC_SR04超声波测距

目录 前言 一、SystemVerilog——下一代硬件设计语言 与Verilog关系 与SystemC关系 二、实验原理 2.1 传感器概述&#xff1a; 2.2 传感器引脚 2.3 传感器工作原理 2.4 整体测距原理及编写思路 三、System-Verilog文件 3.1 时钟分频 3.2 超声波测距 3.3 数码管驱动…

共享购模式:数据驱动的消费增值新体验

共享购模式是一种创新的消费增值系统&#xff0c;它通过整合商家资源&#xff0c;实现商家让利和消费者增值的双重目标。以下是该模式的详细收益分析&#xff1a; 商家让利机制&#xff1a;商家入驻平台需持有价值500元的共享积分作为保证金&#xff0c;确保交易的诚信与质量。…

LabVIEW液压伺服压力机控制系统与控制频率选择

液压伺服压力机的控制频率是一个重要的参数&#xff0c;它直接影响系统的响应速度、稳定性和控制精度。具体选择的控制频率取决于多种因素&#xff0c;包括系统的动态特性、控制目标、硬件性能以及应用场景。以下是一些常见的指导原则和考量因素&#xff1a; 常见的控制频率范…

【介绍下Spark MLlib机器学习】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

Java实现经纬度坐标转换

一、坐标系统简介 坐标系统&#xff0c;是描述物质存在的空间位置&#xff08;坐标&#xff09;的参照系&#xff0c;通过定义特定基准及其参数形式来实现。 坐标是描述位置的一组数值&#xff0c;按坐标的维度一般分为一维坐标&#xff08;公路里程碑&#xff09;和二维坐标…

SpringFramework总结

一.SpringFramework介绍 (一)Spring 广义上的 Spring 泛指以 Spring Framework 为基础的 Spring 技术栈。 Spring 已经不再是一个单纯的应用框架&#xff0c;而是逐渐发展成为一个由多个不同子项目&#xff08;模块&#xff09;组成的成熟技术&#xff0c;例如 Spring Frame…

【机器学习系列】“购物篮分析入门:使用Apyori库进行关联规则挖掘”

目录 一、关联分析介绍 关键概念&#xff1a; 1. 支持度&#xff08;Support&#xff09; 2. 置信度&#xff08;Confidence&#xff09; 3. 提升度&#xff08;Lift&#xff09; 4. 频繁项集 5. 关联规则 应用场景&#xff1a; 实现方法 二、导入数据集 额外介绍一…

实用商务口语:“企业文化”用英语怎么说?柯桥学英语去银泰

企业文化是指企业员工共有的一套观念、信念、价值和价值行为准则&#xff0c;以及由此导致的行为模式。 英文可以说&#xff1a;enterprise / company / corporate culture。 情景对话练习01 A:Your company made a lot of achievements last year; how do you make it? 你们…

开源Mamba-2性能狂飙8倍!多个Mamba超强进化体拿下顶会

MambaOut的热度刚过去没多久&#xff0c;Mamba-2就带着它狂飙8倍的性能炸场了。 Mamba-2的核心层是对Mamba的选择性SSM的改进&#xff0c;同等性能下&#xff0c;模型更小&#xff0c;消耗更低&#xff0c;速度更快。与Mamba不同&#xff0c;新一代的Mamba-2再战顶会&#xff…