当前位置: 首页 > 科技观察

Go程序中的ifelse分支太多?尝试使用策略模式来管理它!

时间:2023-03-14 15:28:55 科技观察

大家好,我是每周都在这里陪你进步的站长。上一篇文章给大家分享了设计模式中的模板模式,告诉大家在项目开发中使用模板模式细化流程,减少重复开发的技巧。同时,在上一篇文章中,我也分享了自己总结的一个暴力理论,即“模板、策略、责任链三种设计模式是解决业务系统复杂多变痛点的利器”过程。”今天我们继续学习策略模式,以及如何用Go代码实现策略模式。什么是策略模式策略模式是一种行为设计模式,通过它可以在运行时修改对象的行为。很多资料中对它的定义是:定义一类算法族,将各个算法分别封装起来,使它们可以相互替换,这种模式使得算法的改变与使用该算法的客户端无关。看完了策略模式的定义,是不是也有一种读等于不读的感觉呢?初读时也是如此。下面我就用一些大白话给大家讲解一下。大白话策略模式策略模式的定义比较抽象,乍一看很难理解。这里说的算法不是我们每天要找工作准备面试的时候用的那种算法;在算法族中定义一类算法族表示要完成的某个任务的分类,比如用户支付,就是一个任务类别。算法族中的每一个算法(即策略)都是指完成这个任务的具体方式。在我们的例子中,我们可以使用支付宝或者微信支付来完成我们定义的用户支付这个任务的两种方法(算法)(算法族)。策略模式主要用来让我们的程序在运行时动态改变一个任务的处理逻辑。常见的应用场景包括针对软件用户群体的不同策略切换(用烂大街的话来表达,千人千面)和业务流程的完全切换。注:这里以支付为例,供大家理解。事实上,在运行时切换支付方式是相当复杂的。实际上,您可以从在运行时将通知切换给用户的任务开始。策略模式要解决的问题是将客户端的使用与具体执行任务的策略解耦。无论使用哪种策略完成任务,都不需要改变客户端使用策略的方式。上面提到的使用策略模式完成任务的整个形式用一个UML图来表示,会比较清晰。策略模式的UML图如下:图中主要有四种角色:客户端:这个客户端可以简单理解为发起者任务调用的代码。抽象策略:就是上面定义的算法族,是所有具体策略的通用接口,声明了用来执行和完成任务的方法。具体策略:实现抽象策略,定义如何完成任务。Context:作为客户端和具体策略之间的中间层,达到客户端和具体策略解耦的效果。它维护对具体策略的引用,只通过抽象策略中定义的接口与具体策略通信。常用的实现方式是结合上面类图中的一个细节。当context对象引用具体的策略类时,使用组合方式,使其私有属性指向策略接口的具体实现,从而在运行时可以修改和执行。特定于任务的策略效果(通过SetStrategy方法)。光看上面的描述和UML图,还是有点单薄。为了便于理解,下面举个更具体的例子。策略模式示例——实现支付策略示例链接,然后以我们上面使用的用户支付任务为例。比如你在购物APP上买东西要付款,客户使用微信支付或者其他第三方在线支付。如果使用策略模式解耦,客户端可以使用相同的调用方式完成支付,甚至在无法使用微信支付的情况下,应用也可以无痛切换到第三方支付完成支付。注意这里的client是上面说的调用context的代码,不是手机APP。在使用代码实现支付策略之前,先用UML类图梳理一下整个实现的大致结构:PayBehavior:抽象策略,支付任务的接口抽象WxPay和ThirdPay:是具体的策略实现PaxCtx:有这里有两个上下文对象,作用一是协调自己持有的PayBehavior的具体实现,完成支付任务,二是维护发起支付所需的支付参数——即图中的私有属性payParams.接下来,我们将这个UML图转化为代码实现。首先,我们定义了PayBehavior策略的接口类型PayBehaviorinterface{OrderPay(px*PayCtx)}。有了接口之后,我们定义两个策略的实现//具体的支付策略实现//微信支付》本文用到的完整可运行源码可以发到公众号《网管比超》【设计模式】到receive"typeWxPaystruct{}func(*WxPay)OrderPay(px*PayCtx){fmt.Printf("Wx支付处理支付请求%v\n",px.payParams)fmt.Println("Wx支付正在用于payment")}//三方支付类型ThirdPaystruct{}func(*ThirdPay)OrderPay(px*PayCtx){fmt.Printf("三方支付处理支付请求%v\n",px.payParams)fmt.Println("使用三方支付进行支付")}策略执行后,必须有上下文来协调它们,并持有完成此任务所必需的输入payParams"本文使用的完整可运行源码去公众号“网络管理叮咚”发送【设计模式】接收“typePayCtxstruct{//提供支付能力的接口implementspayBehaviorPayBehavior//支付参数payParamsmap[string]interface{}}func(px*PayCtx)setPayBehavior(pPayBehavior){px.payBehavior=p}func(px*PayCtx)Pay(){px.payBehavior.OrderPay(px)}funcNewPayCtx(pPayBehavior)*PayCtx{//支付参数,模拟数据参数:=map[string]interface{}{"appId":"234fdfdngj4","mchId":123456,}return&PayCtx{payBehavior:p,payParams:params,}}这些代码都准备好后,我们可以尝试运行line程序调用他们funcmain(){wxPay:=&WxPay{}px:=NewPayCtx(wxPay)px.Pay()//假设现在微信支付没钱,用第三方支付支付thPay:=&ThirdPay{}px.setPayBehavior(thPay)px.Pay()}这个例子的实现比较简单,相信大家都能看懂,我觉得最重要的是理解这个代码框架,后面在实现策略模式项目根据实际情况,到时候可以支持和应用。本文完整源码已同步收录在我整理的电子教程中,您可以将关键字【设计模式】发送到我的公众号「网管叮哭」获取。接下来说说上一篇学习的策略模式和模板模式的区别和关联使用。策略模式和模板模式策略模式和模板模式经常一起使用。策略模式允许完成任务的具体方式相互切换,而模板模式则针对流程的共性整理出固定的执行步骤,并将具体步骤的执行方法委托给子类实现。两者的解耦维度不同。策略模式在抽象方法的实现中经常使用模板模式。或者以我们上面的支付行为为例。上述策略模式定义了一个算法族(支付)和多个具体的算法实现(微信、三方支付),使得支付策略与客户端解耦。我们上面的示例代码比较简单。通常,支付完成后,需要生成带参数的签名,验证客户端发送的签名,调用基础支付服务进行预购和下单。但是,每个基础支付服务在设计的界面和交互过程中可能存在一些细小的差异。这时候我们可以使用签名学习的模板模式来统一支付任务的内部流程步骤。策略模式和模板模式的结合可以让我们写的程序更加健壮。更容易维护。