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

用Go学习设计模式——细化流程,靠它减少重复开发!

时间:2023-03-21 00:20:29 科技观察

大家好,我是网络管理员,今天继续为大家更新设计模式系列。之前更新过四种构造型设计模式。它是完整的。没看过的小伙伴可以点击上方和文末的系列合集链接查看。从今天开始,未来三篇设计模式系列文章,我们所学的设计模式在项目开发中应用率非常高,尤其是针对业务系统重复开发率高,缺乏自底向上的策略对于流程,以及产品需求的无序扩展。在痛点上非常有用。所以在这里我先抛出一个我总结过的暴力理论:“模板、策略、责任链三种设计模式是解决业务系统流程复杂多变痛点的利器”。这三种设计模式应该处理业务系统的重复。对于开发率高、流程无自下而上策略、产品需求无序扩展等几个痛点非常有用。今天先给大家介绍一下模板模式,因为有时候攻略会在步骤中应用到模板模式,所以下一篇再分享。我们先来看看模板模式是什么样子的,使用的时候代码怎么写,最后分析一下如何使用模板模式来分析系统目前存在的问题。什么是模板模式模板模式,有的也翻译成模板方法模式,主要是这种模式中有模板方法,后面在实际应用中会提到,这种模板方法在一些客户端的设计中会用到,服务。在初次交互的场景中,其实是可以虚的。我们可以用自己的意识来设计API,它不必存在于设计模式的类实现中。在做一件事情的时候,这件事情的流程和步骤是固定的,但是每一步的具体实现却不一定。这时候就可以使用模板模式了。模板模式通常的用法是在方法模板方法中定义一个算法或逻辑过程和步骤,比如先调整内部方法A,再调整内部方法B,当满足一定条件时不调整方法C,等等在。流程中每个步骤对应的方法都可以推迟到子类中去实现,这就赋予了程序在不改变大流程和大步骤的情况下完成类似业务的能力。模板模式实现起来非常简单。抽象类用于定义步骤,并提供步骤的默认实现。具体业务逻辑中各个步骤的实现差异可以交给子类实现。模板模式的结构可以用这种方式用UML类图表示。这是我们都见过的业务流程示例。结合代码实现,大家可以更好的理解模板模式的使用方法。如果是Java来实现模板模式,那真的很简单,用抽象类和子类来实现就可以了。网上资料很多,我就不多说了。接下来,我将使用Go代码来实现模板设计模式。主要原因是Go不支持继承,但是也有typeanonymousembedding集合达到了几乎继承的效果,所以代码会写的有些曲折。模板模式使用示例比如我们去银行柜台办理业务,存款、取款、购买理财等业务流程会包括:取号、排名等号、办理业务、服务评价。如果你是金葵花之类的VIP用户,可能会有一个不用排队的独享窗口,检查用户是否是VIP的步骤叫做hook方法。//本文使用的完整可运行源码//进入公众号「网管必唯」发送【设计模式】接收类型BankBusinessHandler接口{//排队取号TakeRowNumber()//等待aseatWaitInHead()//处理具体业务HandleBusiness()//对服务进行评估Commentate()//Hook方法,//用于判断进程中是否为VIP,实现类似VIP的需求checkVipIdentity()bool}模板方法,因为Go不支持抽象类和子类继承。我们通过匿名嵌套类型来实现这一点。BankBusinessHandler接口的实现通过一个外层类型进行封装组合,达到类似抽象类和子类继承的效果。//本文使用的完整可运行源码//去公众号「网管必唯」发送【设计模式】接收typeBankBusinessExecutorstruct{handlerBankBusinessHandler}//模板方法,处理银行业务func(b*BankBusinessExecutor)ExecuteBankBusiness(){//适用于单次与客户端交互的流程//如果需要多次与客户端交互完成整个流程,//每次交互调整相应模板中定义的方法即可操作,并且不需要调用所有方法的模板方法b.handler.TakeRowNumber()Commentate()}template模式下:存款、取款、银行客户业务之间的关系可以清晰的展示在下面的UML图中:接下来我们可以在子类中实现各个银行客户业务的逻辑,但是无论哪个商业离不开取号、等座、做生意、评价服务的大流程。下面我们使用模板模式来实现存款业务的流程。代码如下:《完整可运行源码,私信发送给公众号“网管叮咚”发送【设计模式】接收》typeDepositBusinessHandlerstruct{*DefaultBusinessHandleruserVipbool}//通用方法也可以抽象成BaseBusinessHandler组合成具体的实现类,减少重复代码(达到类似子类继承抽象类的效果)strconv.Itoa(rand.Intn(100))+",注意排队情况,三个排号过后顺延")}func(dh*DepositBusinessHandler)WaitInHead(){fmt.Println("等待中line...")time.Sleep(5*time.Second)fmt.Println("请转到窗口xxx...")}func(*DepositBusinessHandler)HandleBusiness(){fmt.Println("账户存储很多人民币...")}func(dh*DepositBusinessHandler)CheckVipIdentity()bool{returndh.userVip}func(*DepositBusinessHandler)Commentate(){fmt.Println("请给我的服务打分,满意请点击0,满意请按0,(~ ̄▽ ̄)~")}的过程执行存款业务由外部封装类定义的统一模板方法发起调用。"完整可运行源码,私信公众号"网管谢bi范",发送【设计模式】获取"(){dh:=&DepositBusinessHandler{userVip:false}bbe:=NewBankBusinessExecutor(dh)bbe.ExecuteBankBusiness()}在实现上面的存款业务流程时,我们会发现有排队、等待、服务等几种方法评估。实现是相同的。所以可以将它们放在抽象类中,进一步减少代码的重复。但是Go并不是一门完全面向对象的语言,但是我们可以通过匿名嵌套的类型组合来实现类似的效果,把这几个操作的方法通过DefaultBusinessHandler类型实现,再通过具体的实现类进行组合,可以也达到了减少重复执行相同逻辑的效果。"完整的可运行源码,私信公众号"网管叮咚"发送【设计模式】获取"typeDefaultBusinessHandlerstruct{}func(*DefaultBusinessHandler)TakeRowNumber(){fmt.Println("Please拿上你的Pickupcode:"+strconv.Itoa(rand.Intn(100))+",注意排队情况,传号后三个安排顺延")}func(dbh*DefaultBusinessHandler)WaitInHead(){fmt.Println("排队等号...")time.Sleep(5*time.Second)fmt.Println("请转到窗口xxx...")}func(*DefaultBusinessHandler)Commentate(){fmt.Println("请告诉我,满意请按0,满意请按0,(~ ̄▽ ̄)~")}func(*DefaultBusinessHandler)CheckVipIdentity()bool{//returnfalse具体实现类}funcNewBankBusinessExecutor(businessHandlerBankBusinessHandler)*BankBusinessExecutor{return&BankBusinessExecutor{handler:businessHandler}}注意DefaultBusiness上面的Handler并没有实现我们要留给具体子类的HandleBusiness方法,所以DefaultBusinessHandler不能看作是BankBusinessHandler接口的实现。正是因为这个类型只能用于实现类的包装,所以Go语言的类型检查可以帮助我们强制要求HandleBusiness方法必须用存款或取款等子类来实现,这样整个银行的业务流程都可以运行。本文完整源码已同步收录在我整理的电子教程中,您可以将关键字【设计模式】发送到我的公众号「网管叮哭」获取。使用模板模式并不一定推荐有模板方法。这里,我们例子中定义模板方法的方法适用于与客户端单次交互的过程。typeBankBusinessExecutorstruct{BankBusinessHandler}//模板方法,处理银行业务func(b*BankBusinessExecutor)ExecuteBankBusiness(){b.TakeRowNumber()if!b.CheckVipIdentity(){//VIP不需要等待b.WaitInHead()}b.HandleBusiness()b.Commentate()}如果需要和客户端进行更多的交流只需一次交互即可完成整个流程,每次交互操作都可以使用模板中定义的方法。这时候,没有必要定义一个调用所有方法的模板方法。在这种情况下,也可以理解为整个流程使用RESTfulAPI接口的组成,起到了模板方法的作用。互联网C端产品中的典型应用场景,如:用户管理活动API,所有活动可以抽象为:展示活动信息,奖品信息,判断用户资格,参与活动,抽奖,查看中奖记录,以及注销这些步骤的奖品。那么我们可以使用模板设计模式来抽象业务流程,让各种用户活动可以使用一套统一的RESTfulAPI来支撑业务效果。模板和工厂的结合是这里的另一点。在实际开发中,没有一种设计模式是可以独立应用的。很多时候,结合使用几种设计模式来实现项目设计。影响。但是,流程的实现逻辑被模板模式推迟到了子类中。我们大概可以想象,将创建模板子类的任务交给工厂模式更合适。我们应该使用什么样的工厂?一般来说,一个简单的工厂就可以了。在项目之初,一般情况下,我们还没有充分挖掘业务需求和流程,所以一开始不要做太深的细化和抽象,真正需要的时候再升级到抽象。工厂也是必须的。模板方法模式的缺点由于继承关系本身的缺点,如果父类增加一个新的抽象方法,所有的子类都必须重新更改。模板模式这么好,那我们是不是要把它应用到所有进程中呢?当然不是,经过大量的实践,能够将某个核心流程提炼成固定的步骤,才更适合应用。如果细化不到位,就不得不频繁地增加或修改流程中的步骤——即修改代表流程的接口或抽象类中的方法。这时候,如果现有业务中流程的实现类有多个,那么都得做相应的调整。