聊聊设计模式之策略模式 – Java之音
Loading
0

聊聊设计模式之策略模式

前言

这几天大部分同学应该都过完年陆陆续续回到工作岗位了,说到过年,最开心的莫过于与家人团聚了,当然除了与家人团聚,最令人振奋的事情就是发年终奖了。说到发年终奖,那可真是几家欢喜几家愁啊。今天我们要谈的不是年终奖的多少,说多了都是泪啊,我们来聊聊年终奖怎么算。年终奖怎么算,相信每个人心里都比较清楚,因为入职的时候一般都会跟HR谈好年终奖的细节。但是对于财务部的人来说就比较头疼了,毕竟他们要算的可是整个公司的人的年终奖,而且每个人的年终奖的计算方式都不一样,这可怎么办呢?接下来我们就用程序来为财务部的人算下整个公司每个人的年终奖。为了简单起见,我们假设年终奖只跟职工的级别和入职年限有关。我们先不用任何模式实现一个最简单的年终奖算法。

不用模式的年终奖算法

首先我们先定义职工类:

聊聊设计模式之策略模式

职工类只有2个跟奖金计算相关的属性,一个是入职年限seniority,另一个是职位级别rank。其中级别为枚举型Rank,分别有P4,P5,P6三个级别。

接下来我们编写奖金计算类:

聊聊设计模式之策略模式

可以看到我们对于奖金的计算是先分级别,然后对每个级别再细分成不同入职年限进行计算的。比如对于级别为P4的职工来说,工作年限大于1年的,奖金为2000,工作年限小于1年的奖金为1000,以此类推。

最后我们写一个客户端测试一下:

聊聊设计模式之策略模式

结果输出如下:

聊聊设计模式之策略模式

可以看到,对于级别跟入职年限不同的三个人,我们很容易地就计算出了他们的奖金。

虽然年终奖已经算出来了,但是这样实现有没有什么问题呢?首先在这个例子中,我们的级别只有3种,然而在大公司中级别有可能是十几种之多,如果将所有奖金的计算方式都写在一个方法中,那势必会有很多的“if...else...”代码块,很不美观,也很难维护。还有一个问题就是,假如说现在要修改级别为P4的职工的计算方式,那应该怎么办呢?在这种情况下只能直接修改BonusCalculator类的calculateBonus方法,而实际场景中calculateBonus方法可能很复杂,直接在这里面修改的话很容易出现问题。既然如此,有没有比较好的方法能够实现对奖金的计算,又能够适应变化,且便于维护呢?当然有。在这种情况下,我们可以使用策略模式来实现,下文将为大家详细介绍。

策略模式

策略模式是一个计划或者方法,根据给定的输入条件达成一个目标,其意图是将可互换的方法封装在各个独立的类中,并且让每个方法都实现一个公共的操作。这个公共的操作称为策略操作,其实现由各个不同的类完成,这些类的实现虽然不同,但是接口是一致的,因此可以使用相同的接口给用户提供不同的策略进行互换。策略模式可以让一组策略共存,代码互不干扰,同时还将策略的选择逻辑从策略的实现中分离出来。接下来我们就用策略模式来重写上述计算奖金的例子。

使用策略模式

首先我们来定义计算奖金的策略接口:

聊聊设计模式之策略模式

策略接口BonusCalculatorStrategy有2个抽象方法,accept方法用来判断该策略是否可以用来计算传入的Employee实例的奖金,calculateBonus方法则是具体计算奖金的策略。接着我们来实现具体的奖金计算策略,他们都实现BonusCalculatorStrategy接口。我们根据职位级别的不同分别实现不同的奖金计算策略,分别是P4BonusCalculatorStrategy、P5BonusCalculatorStrategy、P6BonusCalculatorStrategy,他们分别用于计算职位为P4、P5、P6的职工的奖金。由于这三种策略的实现大同小异,这里只列出P4奖金计算策略P4BonusCalculatorStrategy的代码:

聊聊设计模式之策略模式

由于P4BonusCalculatorStrategy只计算P4级别的职工的奖金,因此在accept方法的实现中,只有职位为P4的职工才会返回true,表示该级别的职工可以使用该策略计算奖金。而calculateBonus方法的实现则是具体的P4级别的职工的奖金计算方法。P5BonusCalculatorStrategy和P6BonusCalculatorStrategy的实现与P4BonusCalculatorStrategy类似,在此不赘述。

既然具体的计算奖金的策略已经实现了,那么我们该如何进行策略的选择呢?前文说到策略模式将策略的实现与策略的选择分开了,上述只是实现了具体的策略,并没有策略选择的逻辑,因此我们这里再引入一个策略上下文,其作用是对策略进行选择:

聊聊设计模式之策略模式

StrategyContext中持有奖金计算的所有策略,并在静态代码块中初始化所有的奖金计算策略。而getStrategy方法则根据具体的职工实例获取其对应的奖金计算策略,在该方法中,我们遍历了所有的奖金计算策略,调用每种策略的accept方法,如果返回true,则表明该策略适合用于计算该职工的奖金,并将该策略返回给客户端。

最后我们写一个客户端测试一下:

聊聊设计模式之策略模式

其输出如下:

聊聊设计模式之策略模式

可以看到,使用策略模式,我们也可以正确地计算出各个职工的奖金。

策略模式的优点

说了这么多,那么策略模式到底有什么优点呢?我们再回到一开始的问题,假如说现在需要修改P4级别的职工的奖金计算方式,那么我们只需要修改P4BonusCalculatorStrategy这个具体的策略就行了,其他地方都不需要修改,这样一来,修改影响到的只是P4BonusCalculatorStrategy这种策略,其他策略并不会受影响。如果不使用策略模式,那么修改的时候需要在“if...else...”块中进行修改,这无疑是很痛苦的事情,也很容易出错。还有就是如果要增加新的策略,比如说现在要计算P7职工的奖金,使用策略模式只需要增加一种策略的实现类,然后在策略上下文中初始化就行了,如果不使用策略模式,则必须增加额外的“if...else...”代码块,相比较而言,使用策略模式代码的可读性跟可维护性大大提升了。

以上就是策略模式的介绍了。如果觉得这篇文章对你有帮助,可以扫描下方二维码,关注本公众号,获取更多优质原创内容。

聊聊设计模式之策略模式



沉思君利用业余时间整理了海量的视频学习资源,涵盖前后端、大数据、机器学习、运维……在此免费赠送给各位爱学习的小伙伴们,领取方式很简单,只需在公众号后台回复“学习”二字或者点击“原文”链接即可领取。




如果想获取更多学习资源,可以扫描下方二维码,加入读者群,沉思君将不定期分享各种学习资源。

聊聊设计模式之策略模式


最后编辑于:2018/8/16作者: 知音小助手

知音小助手

Java之音网站的小助手,帮助大家整理有价值的文章@@

暂无评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注

arrow grin ! ? cool roll eek evil razz mrgreen smile oops lol mad twisted wink idea cry shock neutral sad ???

服务网站公众号,会定期推送网站优质内容,网站最新动态!

服务网站公众号,会定期推送网站优质内容,网站最新动态!