一、前提
在平时的开发过程中,你是否遇到过以下问题:
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,调用一下第三个处理类进行处理,结果如下:正常。
四、总结
通过工厂模式,将一个功能的多个实现类预装载到Spring服务中,通过某个字段去判断调用那个实现类来进行处理,从而将大量的if-else或switch分支替换掉,可以有效的提高代码的可复用性以及降低复杂度。同时使代码更加简洁。