使用(Map+Function函数式接口)或(注解+策略模式)优化switch case


前言

        在开发中,发现之前的小伙伴在使用switch case时并不优雅,导致一个switch case的代码块超过了上百行代码,给后来者的维护开发工作带来了极大的困扰。

        当我们需要用到switch case作为分支判断时,如果层数是4/5层时其实还好,将代码块抽成方法也比较精简,但是当swicth case的层数越变越多,每增加一个分支都需要在原来的代码块中做修改的话,这并不符合开闭原则,我们就需要一些手段来将其优化了,这里给大家列举两种方式来进行优化。

switch (type){
            case 1 -> method1();
            case 2 -> method2();
            case 3 -> method3();
            case 4 -> method4();
            case 5 -> method5();
            default -> method2();
        }   
}

两种优化方案

1.基于Map+Function函数式接口

       使用Map集合存储类型与方法的对应关系,使用Function函数式接口来简化方法的调用,其中type可以使用枚举类定义,直接上代码:

public class SwitchFactory {
    Map<Integer, Function<Object, Object>> map = new HashMap<>();

    private static SwitchFactory instance;

    // 使用单例模式实例化当前工厂类实例
    public static SwitchFactory getInstance() {
        if (instance == null) {
            synchronized (SwitchFactory.class) {
                if (instance == null) {
                    instance = new SwitchFactory();
                }
            }
        }
        return instance;
    }

    SwitchFactory(){
        // 初始化定义
        map.put(1, this::function1);
        map.put(2, this::function2);
        map.put(3, this::function3);
        map.put(4, this::function4);
    }
    
    // 传入type来获取需要执行的方法,type可以使用枚举类的方式来代替
    public Function<Object, Object> getFunction(Integer type){
        return map.get(type);
    }

    private Object function1(Object data) {
        return "分支1";
    }

    private Object function2(Object data) {
        return "分支2";
    }

    private Object function3(Object data) {
        return "分支3";
    }

    private Object function4(Object data) {
        return "分支4";
    }


}

此时,可以将原本的switch case代码块换成如下代码:

public static void main(String[] args){
        SwitchFactory switchFactory = SwitchFactory.getInstance();
        // type可用枚举类代替
        Integer type=1;
        Map data=new HashMap();
        // 方法调用
        String res =(String) switchFactory.getFunction(type).apply(data);

        System.out.println(res);
}

2.基于注解+Enum+策略模式

        第一种方案只需要创建一个类,然后增加方法就可以了。当业务逻辑十分相似且较为复杂时,我们可以通过策略模式将 “业务逻辑” 进行抽象, 只用一个注解的形式来实现动态增减分支,而开发人员只需关注具体业务逻辑实现即可。

1、首先定义分支条件type的常量值的枚举类CaseEnum

public enum CaseEnum {
    ACCEPT,
    READ,
    WRITE;
}

2. 定义注解CaseAnnotation,这个注解将用于“方法操作逻辑实现类”之上,标记该类是其中一个分支

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CaseAnnotation {
    CaseEnum value();
}

3. 通过策略模式将 “业务逻辑” 进行抽象,定义一个接口,并实现一个分支,其它分支同理

/**
 * @Description: 分支统一接口
 */
public interface CaseInterface {
    String execute(Map<String,Object> data) throws Exception;
}
/**
 * @Description: accept分支逻辑处理
 */
@Component
@CaseAnnotation(value = CaseEnum.ACCEPT)
public class AcceptImpl implements CaseInterface{
    @Override
    public String execute(Map<String, Object> data) throws Exception {
        return "接收逻辑处理";
    }
}

4. 在项目启动的过程中,扫描CaseAnnotation注解获取所有分支实现类,通过 Map<String,CaseInterface> 实现枚举值和分支实现类的映射

/**
 * @Description: 获取spring应用上下文工具类
 */
@Component
public class SpringContextUtil implements ApplicationContextAware {
    private ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        this.context=context;
    }

    //获取spring应用上下文(容器)-进而准备获取相应的bean
    public ApplicationContext getContext(){
        return context;
    }
}
/**
 * @Description: 实现枚举值和分支实现类的映射
 */
@Component
public class InitCaseBeanMapComponent {
    public static Map<CaseEnum,CaseInterface> processMap=new ConcurrentHashMap<>();

    @Autowired
    private SpringContextUtil springContextUtil;

    @PostConstruct
    public void init() {
        //获取那些带上了注解的 处理实现类
        Map<String,Object> map=springContextUtil.getContext().getBeansWithAnnotation(CaseAnnotation.class);

        //添加 case常量值~方法操作逻辑实现类 映射
        for (Object process:map.values()){
            CaseAnnotation annotation=process.getClass().getAnnotation(CaseAnnotation.class);
            processMap.put(annotation.value(),(CaseInterface) process);
        }
    }

    public Map<CaseEnum,CaseInterface> getProcessMap(){
        return processMap;
    }
}

此时,可以将原本的switch case代码块换成如下代码:

Map<String,Object> data = new HashMap<>();

CaseInterface case=InitCaseBeanMapComponent.processMap.get(CaseEnum.ACCEPT);
String res = case.execute(data);


总结

1. 基于Map+Function函数式接口方式,只需要新建一个类,在类中增加分支方法即可,但当业务逻辑较为复杂,类的体积将会变的较大。

2. 基于注解+Enum+策略模式的方式,适合业务逻辑十分相似且较为复杂的场景,可以发现改造过后代码比原本的更多了,但当分支越来越多时,这无疑是值得的

<think>嗯,用户想知道如何创建调用与后端相关的按钮接口,特别是关于后端实现按钮功能的API设计接口调用方法。首先,我需要回忆一下相关的知识,比如如何设计RESTful API,以及前后端如何交互。根据用户提供的引用,特别是引用[1]提到的controller层的作用,应该先考虑后端接口的设计部分。 用户可能是在开发一个Web应用,前端需要有一个按钮,点击后触发某个后端功能。比如提交表单者获取数据。这时候,后端需要提供一个API接口,前端通过Ajax者Fetch来调用这个接口。引用[2]中提到了Ajax调用API的方法,所以可能需要指导用户如何在前端发送请求,并在后端处理这些请求。 首先,API设计部分。需要确定HTTP方法,比如GET、POST等。比如,如果按钮是触发某个动作,比如创建资源,应该用POST方法。然后定义路由路径,比如/api/button-action。请求参数可能需要通过请求体者URL参数传递,后端处理逻辑后返回响应。 然后,后端实现部分。使用Spring Boot的话,需要创建Controller层,处理对应的请求。比如,在Controller中定义一个方法,使用@PostMapping注解,处理POST请求,调用Service层执行业务逻辑,最后返回结果。 前端调用部分,用户可能使用JavaScript,比如原生的Ajax者jQuery,者现代的前端框架如React。引用[2]中的例子是Ajax调用,所以可能需要展示如何绑定按钮的点击事件,发送请求到后端接口,并在回调函数中处理响应结果。 另外,需要注意接口的安全性,比如身份验证和授权,可能需要使用JWT者OAuth2。用户的问题中没有提到安全方面,但作为最佳实践,可能需要提及。 可能还需要考虑错误处理,比如后端如何处理异常,返回合适的HTTP状态码和错误信息,前端如何捕获并展示这些错误。 用户提供的示例中的Python代码可能只是示例,但用户的问题更偏向于Java的Spring Boot,因为引用[1]提到的是Spring Boot的controller层。不过,用户的问题可能更通用,需要涵盖不同后端技术,但根据引用,主要应集中在Spring Boot上。 总结一下,回答应该分步骤:API设计、后端实现、前端调用、安全与优化。每个部分给出具体的例子,比如代码片段,并引用提供的参考文献。同时,生成相关问题,帮助用户进一步学习。</think>### 后端按钮功能的API设计与调用方法 #### 一、API设计原则 1. **RESTful风格** - 使用标准HTTP方法(GET/POST/PUT/DELETE)定义操作类型,例如按钮触发的创建操作使用`POST`方法 - 定义清晰资源路径,如`/api/button-action`表示按钮功能接口 2. **请求参数格式** - 路径参数:`/api/button-action/{id}` - 查询参数:`/api/button-action?type=submit` - 请求体(JSON格式):适用于复杂参数传递 3. **响应规范** - 统一返回JSON格式数据,包含状态码、消息和数据主体 ```json { "code": 200, "message": "操作成功", "data": { /* 返回的具体数据 */ } } ``` #### 二、后端实现步骤(以Spring Boot为例) 1. **Controller层定义接口** 处理按钮点击请求的入口,调用Service层逻辑[^1] ```java @RestController @RequestMapping("/api") public class ButtonController { @Autowired private ButtonService buttonService; @PostMapping("/button-click") public ResponseEntity<?> handleButtonClick(@RequestBody ButtonRequest request) { String result = buttonService.processAction(request.getActionType()); return ResponseEntity.ok().body(Map.of("code", 200, "data", result)); } } ``` 2. **Service层实现业务逻辑** ```java @Service public class ButtonService { public String processAction(String actionType) { switch(actionType) { case "submit": return "执行提交数据库操作"; case "download": return "生成文件下载链接"; default: throw new IllegalArgumentException("未知操作类型"); } } } ``` #### 三、前端调用方法 1. **原生JavaScript调用** 通过`fetch``XMLHttpRequest`发送请求[^2] ```javascript document.getElementById("myButton").addEventListener("click", () => { fetch('/api/button-click', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ actionType: 'submit' }) }) .then(response => response.json()) .then(data => console.log(data)); }); ``` 2. **React框架示例** 使用`axios`库进行接口调用[^3] ```jsx import axios from 'axios'; function ActionButton() { const handleClick = () => { axios.post('/api/button-click', { actionType: 'download' }) .then(response => { console.log('后端返回数据:', response.data); }); }; return <button onClick={handleClick}>执行操作</button>; } ``` #### 四、安全与优化 1. **接口安全措施** - 添加`JWT`身份验证 - 使用`@PreAuthorize`注解进行权限控制 - 参数校验(如Spring Validation) 2. **性能优化建议** - 按钮防重复点击:前端添加加载状态禁用按钮 - 后端异步处理:使用`@Async`注解实现非阻塞操作 - 接口限流:通过Guava RateLimiter控制请求频率
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值