专栏首页Java架构沉思录聊聊设计模式之策略模式

聊聊设计模式之策略模式

前言

这几天大部分同学应该都过完年陆陆续续回到工作岗位了,说到过年,最开心的莫过于与家人团聚了,当然除了与家人团聚,最令人振奋的事情就是发年终奖了。说到发年终奖,那可真是几家欢喜几家愁啊。今天我们要谈的不是年终奖的多少,说多了都是泪啊,我们来聊聊年终奖怎么算。年终奖怎么算,相信每个人心里都比较清楚,因为入职的时候一般都会跟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...”代码块,相比较而言,使用策略模式代码的可读性跟可维护性大大提升了。

以上就是策略模式的介绍了。

本文分享自微信公众号 - 编程沉思录(code-thinker),作者:沉思君

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-02-23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • WebSocket实现Web端即时通信

    HTTP协议是半双工协议,也就是说在同一时间点只能处理一个方向的数据传输,同时HTTP消息也是过于庞大,里面包含大量消息头数据,真正在消息处理中很多数据不是必须...

    黄泽杰
  • 揭秘JDBC超时机制

    在遭到DDos攻击后,整个服务都垮掉了。由于第四层交换机不堪重负,网络变得无法连接,从而导致业务系统也无法正常运转。安全组很快屏蔽了所有的DDos攻击,并恢复了...

    黄泽杰
  • 大白话布隆过滤器

    近期在做推荐系统中已读内容去重的相关内容,刚好用到了布隆过滤器,于是写了一篇文章记录分享一下。

    黄泽杰
  • 【思维导图】什么是敏捷开发?

    0、先来一张导图 ? 1、概念 简单的说,敏捷开发是一种以人为核心、迭代、循序渐进的开发方法。在敏捷开发中,软件项目的构建被切分成多个子项目,各个子项目的成果...

    java思维导图
  • 什么是敏捷开发

    简单的说,敏捷开发是一种以人为核心、迭代、循序渐进的开发方法。在敏捷开发中,软件项目的构建被切分成多个子项目,各个子项目的成果都经过测试,具备集成和可运行的特征...

    菲宇
  • stellar 原

    Actions that change things in Stellar, like sending payments, changing your acco...

    wuweixiang
  • 可能这些是你想要的H5软键盘兼容方案

    最近一段时间在做 H5 聊天项目,踩过其中一大坑:输入框获取焦点,软键盘弹起,要求输入框吸附(或顶)在输入法框上。需求很明确,看似很简单,其实不然。从实验过一些...

    桃翁
  • 【H5】209-可能这些是你想要的H5软键盘兼容方案

    作者最近一段时间在做 H5 聊天项目,过程中踩过一个大坑:输入框获取焦点,软键盘弹起,要求输入框吸附(或顶)在输入法框上。需求很明确,看似很简单,其实不然。作者...

    pingan8787
  • json字符串相关转换方法

    用户3003813
  • 从零开始入门 K8s | Kubernetes API 编程利器:Operator 和 Operator Framework

    导读:本文将从实践出发,结合案例来说明,如何借助 Operator 开发框架来扩展 Kubernetes API。内容主要分为三个部分:首先会简单介绍一下 Op...

    CNCF

扫码关注云+社区

领取腾讯云代金券