设计模式-函数式接口+Map 减少 if else

参考资料

  1. 代码优雅之道——如何干掉过多的if else


一. 前期准备

1.1 标记邮箱种类的接口

import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface MailCategoryAnnotation {

    String mailCode();
}

1.2 邮箱类型区分类

  • 考虑到之后可能会有其他类型的区分,因此使用了内部class
public final class CategoryKbn {

    // 邮件种类
    public final class MailCategory {
        public final static String Mail_163 = "1";
        public final static String Mail_QQ = "2";
        public final static String Mail_G = "3";
        public final static String Mail_OutLook = "4";
    }
	// 其他种类。。。
}

1.3 入参Form实体类

import lombok.Data;

@Data
public class Test27Form {
	
	// 用于标记邮箱的种类
    private String category;
}

二. 邮件发送的业务聚合类

  • 自定义的注解作用在Method上,用来标记邮件发送方法的类型
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
public class SendMailService {
	
    @MailCategoryAnnotation(mailCode = CategoryKbn.MailCategory.Mail_QQ)
    public void sendQQMail(Map<String, String> mailInfoMap) {
        System.out.println("QQ邮箱发送邮件。。。");
        System.out.println(mailInfoMap);
    }

    @MailCategoryAnnotation(mailCode = CategoryKbn.MailCategory.Mail_163)
    public void send163Mail(Map<String, String> mailInfoMap) {
        System.out.println("163邮箱发送邮件。。。");
        System.out.println(mailInfoMap);
    }

    @MailCategoryAnnotation(mailCode = CategoryKbn.MailCategory.Mail_G)
    public void sendGMail(Map<String, String> mailInfoMap) {
        System.out.println("GMail邮箱发送邮件。。。");
        System.out.println(mailInfoMap);
    }

    @MailCategoryAnnotation(mailCode = CategoryKbn.MailCategory.Mail_OutLook)
    public void sendOutLookMail(Map<String, String> mailInfoMap) {
        System.out.println("OutLook邮箱发送邮件。。。");
        System.out.println(mailInfoMap);
    }
}

三. 定义函数式接口,创建邮件发送的Map

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

@Service
public class Test27Service implements InitializingBean {

    @Autowired
    private SendMailService mailService;
	
	/*
		邮件种类code和发送邮件方法的映射Map
	*/
    private final Map<String, MailFunction<Map<String, String>>> strategySendMailMap = new HashMap<>();


    // 标记此接口为函数式编程接口
    @FunctionalInterface
    interface MailFunction<T> {
    	// 不知道参数会是什么类型,就使用了泛型
        void sendMail(T mailInfo) throws Exception;
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {

        for (Method mailSendMethod : Arrays.asList(mailService.getClass().getMethods())) {			
        	// 如果该方法上没有被标记MailCategoryAnnotation自定义注解就跳过
            if (!mailSendMethod.isAnnotationPresent(MailCategoryAnnotation.class)) {
                continue;
            }
			
			// 获取Method上被标记的MailCategoryAnnotation注解上的mailCode
            String mailCode = mailSendMethod.getAnnotation(MailCategoryAnnotation.class).mailCode();
            
            // 将mailcode和发送邮件的方法添加到Map中
            strategySendMailMap.put(mailCode, (T) -> mailSendMethod.invoke(mailService, T));
        }
    }


    public void execute(String category) throws Exception {
    	
    	// 发送邮件时所需要的参数
    	Map<String, String> mailInfoMap = new HashMap<>() {
            {
                put("id", "110120");
                put("name", "jiafeitian");
            }
        };
        
        // 根据category获取邮件的发送方法,并执行
        MailFunction<Map<String, String>> sendMailFunction = strategySendMailMap.get(category);
        sendMailFunction.sendMail(mailInfoMap);
    }
}

四. 效果

⏹前台

const jsonData = {
    category: '2'
};

$.ajax({
    url: "/test27/test1",
    type: 'POST',
    data: JSON.stringify(jsonData),
    contentType: 'application/json;charset=utf-8',
    success: function (data, status, xhr) {
        console.log(data);
    }
});

⏹后台

import org.springframework.web.bind.annotation.*;
import org.springframework.http.ResponseEntity;

@PostMapping("/test1")
public ResponseEntity<Void> test1(@RequestBody Test27Form form) throws Exception {

    service.execute(form.getCategory());
    return ResponseEntity.noContent().build();
}

👇效果

在这里插入图片描述


五. 小结

上述的简化if else的方法本质上使用了函数式编程中的Consumer消费方法,该方法可放到Map中进行映射,可根据Map中的key动态灵活的执行方法,从而减少分支。

import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;

import javax.annotation.PostConstruct;

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Controller;

@Controller
public class ConsumerTestController implements CommandLineRunner {
    
    // 定义code和Consumer消费方法的映射
    private final Map<String, Consumer<String>> strategySendMailMap = new HashMap<>();
    
    @PostConstruct
    private void init() {
        
        // 定义了一个消费方法,对传入的参数str进行消费,消费方法无返回值
        Consumer<String> printInfo1 = (String str) -> {
            System.out.println(str);
            System.out.println("printInfo1");
        };
        
        Consumer<String> printInfo2 = (String str) -> {
            System.out.println(str);
            System.out.println("printInfo2");
        };
        
        // 类似于JavaScript中的Map映射
        strategySendMailMap.put("a", printInfo1);
        strategySendMailMap.put("b", printInfo2);

        /*
            相当于这种写法的简写模式
            strategySendMailMap.put("c", (String str) -> ConsumerTestController.printInfo3(str));
         */
        strategySendMailMap.put("c", ConsumerTestController::printInfo3);
    }
    

    @Override
    public void run(String... args) throws Exception {

        // 模拟根据参数然后从Map映射中获取消费函数
        Consumer<String> consumer = strategySendMailMap.get("c");
        // 传入参数,执行消费函数
        consumer.accept("你好");
    }
    
    public static void printInfo3(String str) {
        System.out.println(str);
        System.out.println("printInfo3");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这段代码是一个六子棋的评估函数,用于计算当前局面的分值。以下是逐行解释: ``` int evaluate() { int score = 0; int color = currBotColor; ``` 定义一个变量score来记录分值,color来记录当前颜色(黑色或白色)。 ``` for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { if (gridInfo[i][j] == grid_blank) continue; ``` 遍历棋盘上的每个位置,如果该位置为空,则跳过。 ``` int cnt = 1; for (int k = 0; k < 8; k++) { int nx = i + dx[k], ny = j + dy[k]; if (!inMap(nx, ny) || gridInfo[nx][ny] != color) continue; cnt++; int nnx = nx + dx[k], nny = ny + dy[k]; if (inMap(nnx, nny) && gridInfo[nnx][nny] == color) cnt++; } ``` 对于每个非空位置,统计该位置周围八个方向上连续的同色棋子数,用变量cnt来记录。 ``` if (cnt >= M) score += color == currBotColor ? INF : -INF; else if (cnt == M - 1) score += color == currBotColor ? 10000 : -10000; else if (cnt == M - 2) score += color == currBotColor ? 1000 : -1000; else if (cnt == M - 3) score += color == currBotColor ? 100 : -100; else if (cnt == M - 4) score += color == currBotColor ? 10: -10; else if (cnt == M - 5) score += color == currBotColor ? 1: -1; ``` 根据连续的同色棋子数cnt来计算分值,分值会根据棋子数的不同而不同。如果cnt大于等于M(代表连成了一条五子连珠),则分值为正无穷或负无穷;如果cnt等于M-1(代表连成了一条四子连珠),则分值为10000或-10000;以此类推,直到cnt等于M-5(代表连成了一条一子连珠),此时分值为1或-1。 ``` color = -color; } } ``` 统计完一个颜色的分值后,切换颜色。 ``` return score; } ``` 返回最终的分值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值