一、前提

在平时的开发过程中,你是否遇到过以下问题:

1.sonar扫描代码圈复杂度过高,需要减少if-else分支及switch分支。

2.某个类中/某个方法的代码太多,难以维护。

代码中业务分支过多时,代码可读性会变得很差,大量的代码堆积在一个类中,也会变得难以维护。

遇到这些问题,说明你:该拆分啦!!

使用Spring的工厂管理+策略模式可以很好的解决这个问题。

二、策略模式的介绍

策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。比如每个人都要“交个人所得税”,但是“在美国交个人所得税”和“在中国交个人所得税”就有不同的算税方法。

在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。

三、实战应用

1.我们的应用场景:首先,假设我们这有一个非常复杂的类,里面有很多个分支,我们想通过spring工厂+策略模式减少分支代码。改造前的代码如下:

package com.ampthon.api.impl;

import org.springframework.stereotype.Service;

@Service
public class FuncApiImpl {

    /**
     * 假设有数十个分支,每个分支的处理方法都有100行,那么这个类就可能有1000行
     * 所有的功能模块都写在一起,这样会造成程序的高耦合,低内聚,可维护性差,代码复杂度高
     *
     * @param type 业务类型
     * @return
     */
    public String funcDeal(String type) {
        String result = "";
        switch (type) {
            case "aaaa":
                result = funcA();
                break;
            case "bbbb":
                result = funcB();
                break;
            case "cccc":
                result = funcC();
                break;
            case "...."://假设有数十个分支,每个分支的处理方法都超过100行
                result = "....";
                break;
            default:
                break;

        }
        return result;
    }
    
    public String funcA() {
        return "aaaa";
    }

    public String funcB() {
        return "bbbb";
    }

    public String funcC() {
        return "cccc";
    }

}

2.代码改造:

主函数代码:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;


@SpringBootApplication
@ComponentScan("com.ampthon")
public class Application {

    public static void main(String[] args) {
        System.out.println("项目开始启动");
        SpringApplication.run(Application.class);
        System.out.println("项目启动完成");


    }
}

controller代码:

package com.ampthon.controller;

import com.ampthon.api.FuncApi;
import com.ampthon.factory.StrategyFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class FuncController {

    @Autowired
    private StrategyFactory factory;

    @PostMapping("/getData")
    public String getData(String funcName){
        String result = "";
        try {
            FuncApi api =  factory.getApiByFuncName(funcName);
            result = api.funcDeal();
        } catch (Exception e) {
           e.printStackTrace();
        }
        return result;
    }
}

将原有impl类拆分为一个api,多个实现类。

api类代码:

package com.ampthon.api;

public interface FuncApi {

    public String funcDeal();

    public String getFuncName();

}

api实现类代码:

实现类1:

package com.ampthon.api.impl;

import com.ampthon.api.FuncApi;
import org.springframework.stereotype.Service;

@Service
public class FuncOneApiImpl implements FuncApi {

    @Override
    public String funcDeal() {
        return "this is funcOne result";
    }

    @Override
    public String getFuncName(){
        return "funcOneApiImpl";
    }

}

实现类2:

package com.ampthon.api.impl;

import com.ampthon.api.FuncApi;
import org.springframework.stereotype.Service;

@Service
public class FuncTwoApiImpl implements FuncApi {

    @Override
    public String funcDeal() {
        return "this is funcTwo result";
    }

    @Override
    public String getFuncName(){
        return "funcTwoApiImpl";
    }

}

实现类3:

package com.ampthon.api.impl;

import com.ampthon.api.FuncApi;
import org.springframework.stereotype.Service;

@Service
public class FuncThreeApiImpl implements FuncApi {

    @Override
    public String funcDeal() {
        return "this is funcThree result";
    }

    @Override
    public String getFuncName(){
        return "funcThreeApiImpl";
    }

}

工厂类:

package com.ampthon.factory;

import com.ampthon.api.FuncApi;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;

@Component
public class StrategyFactory implements InitializingBean{


    @Autowired
    private ApplicationContext applicationContext;

    //策略map
    public static Map<String,FuncApi> strategyMaps = new HashMap<>();

    //根据功能名称获取对应的实现类进行处理
    public FuncApi getApiByFuncName(String funcName) throws Exception{
        FuncApi api = strategyMaps.get(funcName);
        if(null==api){
            throw new Exception("not matched api");
        }
        return api;
    }

    //启动时将所有处理类加载好由spring进行管理
    @Override
    public void afterPropertiesSet() throws Exception {
        Map<String, FuncApi> beansOfFuncType = applicationContext.getBeansOfType(FuncApi.class);
        for(Map.Entry<String,FuncApi> entry:beansOfFuncType.entrySet()){
            strategyMaps.put(entry.getKey(),entry.getValue());
        }
    }
}

3.启动程序,进行演示:

我们输入funcThreeApiImpl,调用一下第三个处理类进行处理,结果如下:正常。

java策略模式代码结合自动注入_策略模式

 四、总结

通过工厂模式,将一个功能的多个实现类预装载到Spring服务中,通过某个字段去判断调用那个实现类来进行处理,从而将大量的if-else或switch分支替换掉,可以有效的提高代码的可复用性以及降低复杂度。同时使代码更加简洁。