• Java使用Function包&策略模式,优化大量if...else语句


    目录

    场景模拟

    Consumer与ToIntBiFunction简介,u>

     场景Demo业务代码改造

    最终结果


    业务代码中,若存在大量无法避免的if...else代码,可以尝试使用JDK8提供的函数式编程包。


    场景模拟

    设计一个简单的招聘业务:

    招聘条件是:男18~60岁,女18~50岁。再根据男女不同年龄段,分配不同的事情任务做。

    模拟代码如下

    1. package cn.daydayup.designmode.factorymode.demov4;
    2. /**
    3. * @author ShangHai
    4. * @desc
    5. */
    6. public class Demo {
    7. /**
    8. * 模拟招聘业务
    9. * @param sex 性别
    10. * @param age 年龄
    11. * @param name 名字
    12. */
    13. public void recruit(String sex, int age, String name){
    14. if(CommonConstants.MAN.equals(sex)){
    15. // 男性
    16. if(age > CommonConstants.SIXTY){
    17. throw new RuntimeException("年龄不满足");
    18. } else if(age > CommonConstants.FORTY_FIVE){
    19. this.doSomeThings001(name);
    20. } else if(age >= CommonConstants.THIRTY){
    21. this.doSomeThings002(name);
    22. } else if(age >= CommonConstants.EIGHTEEN){
    23. this.doSomeThings003(name);
    24. } else {
    25. throw new RuntimeException("年龄不满足");
    26. }
    27. } else if(CommonConstants.WOMAN.equals(sex)) {
    28. // 女性
    29. if(age > CommonConstants.FIFTY){
    30. throw new RuntimeException("年龄不满足");
    31. } else if(age >= CommonConstants.THIRTY){
    32. this.doSomeThings004(name);
    33. } else if(age >= CommonConstants.EIGHTEEN){
    34. this.doSomeThings005(name);
    35. } else {
    36. throw new RuntimeException("年龄不满足");
    37. }
    38. } else {
    39. throw new RuntimeException("性别不满足");
    40. }
    41. }
    42. private void doSomeThings001(String name){
    43. System.out.println(name + "[男]年龄45-60");
    44. }
    45. private void doSomeThings002(String name){
    46. System.out.println(name + "[男]年龄30-45");
    47. }
    48. private void doSomeThings003(String name){
    49. System.out.println(name + "[男]年龄18-30");
    50. }
    51. private void doSomeThings004(String name){
    52. System.out.println(name + "[女]年龄30-60");
    53. }
    54. private void doSomeThings005(String name){
    55. System.out.println(name + "[女]年龄18-30");
    56. }
    57. }

    常量代码 

    1. package cn.daydayup.designmode.factorymode.demov4;
    2. /**
    3. * @author ShangHai
    4. * @desc
    5. */
    6. public class CommonConstants {
    7. public final static int ZERO = 0;
    8. public final static int ONE = 1;
    9. public final static int TWO = 2;
    10. public final static int THRRE = 3;
    11. public final static int FOUR = 4;
    12. public final static int FIVE = 5;
    13. public final static int EIGHTEEN = 18;
    14. public final static int THIRTY = 30;
    15. public final static int FORTY_FIVE = 45;
    16. public final static int FIFTY = 50;
    17. public final static int SIXTY = 60;
    18. public final static String MAN = "男";
    19. public final static String WOMAN = "女";
    20. }

     main方法执行【控制台:GeGeDa[男]年龄45-60

    1. public static void main(String[] args) {
    2. // 控制台输出:​ 【GeGeDa[男]年龄45-60】
    3. new Demo().recruit(CommonConstants.MAN, 49, "GeGeDa");
    4. }

    上述的业务方法中,存在较多的if...else条件语句。

    若条件维度根据业务需求增多,if...else语句将会不断叠加,业务代码将变得不再优雅。

    分析以上业务代码,可采用Function包中的Consumer与ToIntBiFunction配合进行改造。


    Consumer与ToIntBiFunction简介

    Consumer

    Consumer接口是java.util.function包的其中一个接口,

    包含一个核心方法accept(T t),其意义即传入一个参数进行消费,无返回值。


    代码测试如下:

    1. package cn.daydayup.designmode.factorymode.demov4.test;
    2. import java.util.function.Consumer;
    3. /**
    4. * @author ShangHai
    5. * @desc
    6. */
    7. public class TestConsumer {
    8. public static void main(String[] args) {
    9. Consumer consumer = a -> {
    10. System.out.println("输出参数值:" + a);
    11. };
    12. // 传入字符串参数
    13. consumer.accept("aaaa");
    14. }
    15. }

    以上consumer对象声明的方式,等同于

    1. Consumer consumer = new Consumer() {
    2. @Override
    3. public void accept(String a) {
    4. System.out.println("输出参数值:" + a);
    5. }
    6. };

    main方法执行【控制台:输出参数值:aaaa

     ToIntBiFunction

    ToIntBiFunction接口是java.util.function包的其中一个接口,

    包含一个核心方法applyAsInt(T t,U u),其意义即传入两个参数进行消费,返回一个int值。


    代码测试如下:

    1. package cn.daydayup.designmode.factorymode.demov4.test;
    2. import cn.daydayup.designmode.CommonConstant;
    3. import cn.daydayup.designmode.factorymode.demov4.CommonConstants;
    4. import java.util.function.ToIntBiFunction;
    5. /**
    6. * @author ShangHai
    7. * @desc
    8. */
    9. public class TestToIntBiFunction {
    10. public static void main(String[] args) {
    11. // 传入两个String参数,得到一个int值
    12. ToIntBiFunction toIntBiFunction = (a, b) -> {
    13. if(a.equals(b)){
    14. return CommonConstants.ONE;
    15. } else {
    16. return CommonConstants.TWO;
    17. }
    18. };
    19. // 传入两个字符串参数
    20. int result = toIntBiFunction.applyAsInt("参数1", "参数2");
    21. System.out.println("得到的int值" + result);
    22. }
    23. }

    以上toIntBiFunction对象声明的方式,等同于

    1. ToIntBiFunction toIntBiFunction = new ToIntBiFunction() {
    2. @Override
    3. public int applyAsInt(String a, String b) {
    4. if(a.equals(b)){
    5. return CommonConstants.ONE;
    6. } else {
    7. return CommonConstants.TWO;
    8. }
    9. }
    10. };

    main方法执行【控制台:得到的int值2


     场景Demo业务代码改造

    一、if条件&逻辑代码抽离

    创建一个策略列表业务执行类RecruitConsumer,

    用来存储if标签体内实际的执行方法。

    1. package cn.daydayup.designmode.factorymode.demov4.function;
    2. import cn.daydayup.designmode.factorymode.demov4.CommonConstants;
    3. import java.util.HashMap;
    4. import java.util.Map;
    5. import java.util.function.Consumer;
    6. /**
    7. * @author ShangHai
    8. * @desc
    9. */
    10. public class RecruitConsumer {
    11. // 策略列表
    12. public static final Map> CONSUMER_MAP = new HashMap<>();
    13. static {
    14. // 根据传入不同的int值,将执行不同方法
    15. CONSUMER_MAP.put(CommonConstants.ONE, RecruitConsumer::doSomeThings001);
    16. CONSUMER_MAP.put(CommonConstants.TWO, RecruitConsumer::doSomeThings002);
    17. CONSUMER_MAP.put(CommonConstants.THRRE, RecruitConsumer::doSomeThings003);
    18. CONSUMER_MAP.put(CommonConstants.FOUR, RecruitConsumer::doSomeThings004);
    19. CONSUMER_MAP.put(CommonConstants.FIVE, RecruitConsumer::doSomeThings005);
    20. }
    21. private static void doSomeThings001(String name){
    22. System.out.println(name + "[男]年龄45-60");
    23. }
    24. private static void doSomeThings002(String name){
    25. System.out.println(name + "[男]年龄30-45");
    26. }
    27. private static void doSomeThings003(String name){
    28. System.out.println(name + "[男]年龄18-30");
    29. }
    30. private static void doSomeThings004(String name){
    31. System.out.println(name + "[女]年龄30-60");
    32. }
    33. private static void doSomeThings005(String name){
    34. System.out.println(name + "[女]年龄18-30");
    35. }
    36. }

    创建一个"条件收集&策略数值"返回类RecruitToIntBiFunction,

    用来收集需求下所有的if分支,且根据if满足的条件返回一个策略列表需要的策略int数值。

    1. package cn.daydayup.designmode.factorymode.demov4.function;
    2. import cn.daydayup.designmode.CommonConstant;
    3. import cn.daydayup.designmode.factorymode.demov4.CommonConstants;
    4. import java.util.function.ToIntBiFunction;
    5. /**
    6. * @author ShangHai
    7. * @desc
    8. */
    9. public class RecruitToIntBiFunction implements ToIntBiFunction{
    10. @Override
    11. public int applyAsInt(Object o, Object o2) {
    12. if(o==null || o2==null){
    13. // 返回0,RecruitConsumer策略列表不具备0策略,不执行任何逻辑
    14. return CommonConstants.ZERO;
    15. }
    16. String sex = o.toString();
    17. int age = Integer.parseInt(o2.toString());
    18. if(CommonConstants.MAN.equals(sex)){
    19. // 男性
    20. if(age > CommonConstants.SIXTY){
    21. // 返回0,RecruitConsumer策略列表不具备0策略,不执行任何逻辑
    22. return CommonConstants.ZERO;
    23. } else if(age > CommonConstants.FORTY_FIVE){
    24. return CommonConstants.ONE;
    25. } else if(age >= CommonConstants.THIRTY){
    26. return CommonConstants.TWO;
    27. } else if(age >= CommonConstants.EIGHTEEN){
    28. return CommonConstants.THRRE;
    29. } else {
    30. // 返回0,RecruitConsumer策略列表不具备0策略,不执行任何逻辑
    31. return CommonConstants.ZERO;
    32. }
    33. } else if(CommonConstants.WOMAN.equals(sex)) {
    34. // 女性
    35. if(age > CommonConstants.FIFTY){
    36. // 返回0,RecruitConsumer策略列表不具备0策略,不执行任何逻辑
    37. return CommonConstants.ZERO;
    38. } else if(age >= CommonConstants.THIRTY){
    39. return CommonConstants.FOUR;
    40. } else if(age >= CommonConstants.EIGHTEEN){
    41. return CommonConstants.FIVE;
    42. } else {
    43. // 返回0,RecruitConsumer策略列表不具备0策略,不执行任何逻辑
    44. return CommonConstants.ZERO;
    45. }
    46. } else {
    47. // 返回0,RecruitConsumer策略列表不具备0策略,不执行任何逻辑
    48. return CommonConstants.ZERO;
    49. }
    50. }
    51. }

    二、业务逻辑代码改造(最终仅需两行)

    1. package cn.daydayup.designmode.factorymode.demov4;
    2. import cn.daydayup.designmode.factorymode.demov4.function.RecruitConsumer;
    3. import cn.daydayup.designmode.factorymode.demov4.function.RecruitToIntBiFunction;
    4. /**
    5. * @author ShangHai
    6. * @desc
    7. */
    8. public class Demo {
    9. /**
    10. * 模拟招聘业务
    11. * @param sex 性别
    12. * @param age 年龄
    13. * @param name 名字
    14. */
    15. public void recruit(String sex, int age, String name){
    16. // 将if条件所需参数传入,得到策略int数值
    17. int strategyInt = new RecruitToIntBiFunction().applyAsInt(sex, age);
    18. // 将策略int数值传入策略列表,consumer会自动执行对应的策略方法
    19. RecruitConsumer.CONSUMER_MAP.get(strategyInt).accept(name);
    20. }
    21. public static void main(String[] args) {
    22. // 控制台输出 ShangHai[男]年龄18-30
    23. new Demo().recruit(CommonConstants.MAN, 18, "ShangHai");
    24. }
    25. }

     main方法执行【控制台:ShangHai[男]年龄18-30


    最终结果

    业务方法经过"Funtion包与策略模式"改造后,

    代码变得简洁;

    业务方法不再关注if如何实现,交由定义好的策略消费即可;

    if...else分支语句及业务实际执行方法分类被收集,代码整体层次变得规范。

  • 相关阅读:
    电脑重装系统后Word表格自动换行的方法
    计算机毕业设计源码丨基于java的企业人力资源(人事)管理系统
    基于Java的城市桥梁道路管理系统(Vue.js+SpringBoot)
    【教3妹学编程-java实战4】Map遍历删除元素的几种方法
    王道数据结构C语言循环链表基本操作实现
    【Spring Boot项目】根据用户的角色控制数据库访问权限
    关于二阶低通滤波的C代码及入门测试
    Springboot+网上眼镜商场 毕业设计-附源码241659
    Java:实现动态数组类算法(附完整源码)
    Android 12添加系统服务
  • 原文地址:https://blog.csdn.net/ShangHai0123/article/details/127672277