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

摊牌!策略模式在项目设计中用的多吗?

时间:2023-03-18 23:31:22 科技观察

本文转载自微信公众号“源码兴趣圈”,作者:龙泰。转载本文请联系源码兴趣圈公众号。在日常编码过程中,存在三种设计模式:模板、构建器和策略。今天第三种策略设计模式比较简单,用的也比较多。我们通常使用策略模式来消除if-else、switch等多重判断代码,消除if-else和switch多重判断可以有效应对代码的复杂度,实现设计解耦。开闭原则提高了代码的可扩展性(策略模式场景主要负责解耦,开闭原则需要额外支持)。下面将详细介绍如何使用设计模式做一个demo,模式的真实场景,以及策略模式的好处策略设计模式大纲如下:什么是策略模式?Spring项目中的真实应用场景框架源码。如何玩转策略模式?,封装每一个,并使它们可以互换。策略让算法独立于使用它的客户而变化。定义一组算法类,分别封装每个算法,使它们可以相互替代。策略模式使这些算法能够在客户端调用它们时相互独立地改变。客户端指的是使用该算法的代码。看到上面的介绍,可能还不太清楚什么是策略模式。这里我们将从最基本的代码开始。从现在开始,一步步掌握这个模型。您或许可以将以下代码与相应的业务相关联。根据对应的折扣类型,对价格进行相应的折扣可以满足项目的业务需求,很多已经上线生产环境的代码也有这样的代码。但是这段代码有两个缺点:代码的复杂性,正常的业务代码逻辑肯定会比这段代码块复杂很多,导致if-else分支和代码过多。这种方法可以通过将代码拆分成独立的函数或类来解决开闭原则,而且价格优惠肯定会随着不同的时期而变化,可能会增删改查。如果在一个函数中修改无疑是一件很可怕的事情,想想可能多个开发者各自开发,乱七八糟的注释,混乱的代码逻辑等等十有八九会发生。如何使用策略模式对上面的代码进行优化,使程序的设计着眼于简洁性、可扩展性等特性来简化代码的复杂性,将不同类型的折扣定义为不同的策略算法,实现类来保证开闭原则,增加了程序的健壮性和可扩展性。策略模式实例改造上面的代码块为一个策略设计一个模式,一般需要三个步骤来定义一个抽象的策略接口,因为如果业务使用接口而不是具体的实现类,可以灵活地替换不同的策略来定义一个具体的策略实现类,实现一个自抽象的策略接口,其内部封装具体的业务实现定义策略工厂,封装创建策略实现(算法),对客户端屏蔽具体的创建细节。目前已经创建了抽象策略接口、具体策略实现类和策略工厂。现在你可以看看客户的需求了。如何调用,如何对客户端屏蔽具体实现细节根据代码块图,从策略工厂获取具体策略类,确实取消了if-else设计??,实现了Map存储策略在工厂里。获取策略类后,执行具体的优惠策略方法,获取优惠金额。通过分析,我们知道目前的设计确实降低了应用代码的复杂度。如果添加优惠策略,只需要添加一个策略算法实现类即可。但是,增加一个策略算法实现意味着策略工厂中的代码需要改动,仍然不符合开闭原则。如何完整的实现符合开闭原则的策略模式,需要Spring的帮助。详细案例请继续关注项目。真实应用场景最近一个项目中设计的一个功能使用了strategy模式,分为两种角色。作者负责定义抽象策略接口和策略工厂。每个业务方需要实现不同的策略算法。大家可以想到上面的打折券功能。因为是Spring项目,所以按照Spring的方式处理。话不多说,大家可以看上面的代码。与上面的示例代码相比,有两个明显的变化。在抽象策略接口中,新定义了mark()。接口,该接口用于标记算法的唯一性,具体的策略实现类用@Component修饰,对象本身交给Spring管理。返回标签时最好使用枚举定义。接下来继续看如何改造抽象策略工厂来满足开闭原则。和之前的责任链模型是一样的。就是通过InitializingBean接口的实现调用IOC容器找到对应的策略实现,然后将策略实现中的mark()方法的返回值作为key,将策略实现本身添加到将容器映射为等待客户调用折扣价的值。插曲:如果你不想将策略工厂注入到Spring中,你可以这样做。实现方式多种多样,满足开闭原则。具体来说,就是通过抽象的策略算法类来降低代码的复杂度,然后通过Spring的一些特性,同时满足开闭原则。既然新的需求来了,就增加一个新的策略类。源码底层怎么玩健壮易扩展自己用攻略模式肯定是不行的。必要的时候还得看看设计开源框架源码的大佬们是如何在代码中使用策略模式的。从笔者的理解来看,JDK、Spring、SpringMvc、Mybatis、Dubbo等都用到了策略。设计模式,这里我以Mybatis为例说明,Mybatis中的Executor代表执行者,负责具体的增删改查操作。使用了两种设计模式,模板方法和策略模式Executor代表抽象的策略接口。刚刚提到的模板方法模式来自于BaseExecutorConfiguration,它代表策略工厂,负责创建具体的策略算法实现类SimpleExecuto,ReuseExecutor……代表封装,具体的策略算法实现类在上面有介绍。上面的代码块发生在Configuration类中创建执行器Executor,根据executorType判断创建不同的策略算法。上面的代码块并没有完全杜绝if-else,因为Mybatis中的executor策略基本是固定的,也就是说只会有这些if-else判断,基本不会添加修改。如果一定要去掉if-else,可以这样搞。这是一个伪代码。这种方法称为“查表法”,通过策略工厂消除if-else分支。最后,Mybatis过于详细的设计这里不再赘述。感兴趣的朋友可以下载源码啃。有些读者可能会在这里看到问题。就算策略模式去掉了if-else,但是如果再增加一个新的策略类,不还是会违反开闭原则吗?是的,因为Mybatis本身没有引入Spring依赖,所以没有办法借助IOC容器来实现开闭原理。Spring是一种基于开闭原则的解决方案。还有其他解决办法吗?有很多解决方案。开闭原则的核心是修改关闭原有代码,对新代码开放。可以扫描指定包下的自定义注解或者使用instanceof判断是否继承自某个接口。但是,如果项目使用了Spring,它就会停止。文章在结语中用图文介绍了策略模式,然后引用了本文的重点:通过优惠价场景的策略设计模式。该模式的本质仍然是对代码设计进行解耦,策略模式贯穿于三类角色:抽象策略接口、策略工厂和具体的策略实现类。通过细粒度的策略实现类,避免了过多的代码,降低了设计的复杂度。并且通过开闭原则的特性,在添加新的策略时,可以保证代码的最小化和集中修改。笔者听说很多小伙伴认为自己做的就是CRUD工作,没有挑战性,也比较枯燥。其实我想说的是:业务代码有多好,也能体现程序员的水平。高并发、大数据等场景不一定需要。有不扫一屋扫天下之意。最后提出一个问题:如果有if-else代码,一定要用策略模式优化吗?如果if-else判断分支不多,是固定的,以后不会再出现新的分支,那么我们可以通过抽取函数来降低程序的复杂度;不要试图删除if-else语句,它的存在是合理的。而且,策略模式的使用会导致更多的类。对于少量的判断分支不需要引入策略模式。这篇文章是关于策略设计模式的。后期会陆续输出工厂、原型、享元等图案;如果文章对你有帮助,那就关注和支持吧,祝福。文章参考:《设计模式之美:策略模式》