使用Spring来优雅的替换代码中过多的ifelse

场景

平时我们在写代码时,需要针对不同情况处理不同的业务逻辑,用得最多的就是if和else。 但是如果情况太多,就会出现一大堆的“if
else”,导致整个系统后期维护,升级,或者修改BUG变得很困难。

举个例子,短信发送业务的实现,一般公司会接入多个短信供应商,比如梦网、玄武、阿里云等多个短信平台(我们称之为短信渠道),可能需要针对不同的短信类型或者短信平台的稳定性来切换短信渠道:

比如阿里云短信管控很严,带营销字样的短信不让发送,则营销类短信需要使用其他短信渠道来发送;
也有可能某个短信平台服务挂了暂时不可用,需要切换到另一个短信渠道; 某些短信平台有优惠,则需要临时切换到该短信渠道发送短信; …

烂代码实例

有一个短信发送类:TestService ,里面有一个send方法发送短信。

TestService.java

public class TestService{
	/**
 	 * @Param phoneNo 手机号
	 * @Param content 短信内容
	 */
	public void send(String TypeName,String phone,String content){
		//如果是短信渠道A,则调用渠道A的api发送
		if(TypeName.equals("渠道A")){
			System.out.println("通过短信渠道A发送短信");
		}
		//如果是短信渠道B,则调用渠道B的api发送
		else if(TypeName.equals("渠道B")){
			System.out.println("通过短信渠道B发送短信");
		}
	}
}

如果某天增加了一个短信渠道C,那么接着追加一个”else if…"

//... 此处省略部分代码 ...

//ADD: 如果是短信渠道C,则调用渠道C的api发送
else if(TypeName.equals("渠道C")){
	System.out.println("通过短信渠道C发送短信");
}
//... 此处省略部分代码 ...

如果又加其他短信渠道了呢?你又写一个“else if …" ? 显然这种做法不可取,也不符合SOLID原则中的”开闭原则“
——对扩展开放,对更改封闭。 这样我们每次都需要修改原有代码(对更改没有封闭),不断的添加”if else"。

我们使用spring来优化 代码

1:短信渠道接口 TestInterface.java


public interface TestInterface {
 
 //发送的方法
 void send(String phone,String content);
 
 //获取发送类型的方法
 String getType();
 
}

短信渠道A TestImpl.java

@Service
public class TestImpl implements TestInterface {

    @Override
    public void send(String phone, String content) {
        System.out.println("电话"+phone+"信息"+content+"渠道A");
    }

    @Override
    public String getType() {
        return "A渠道";
    }
    
}

短信渠道B TestImpl02.java

@Service
public class TestImpl02 implements TestInterface {

    @Override
    public void send(String phone, String content) {
        System.out.println("电话"+phone+"信息"+content+"渠道B");
    }

    @Override
    public String getType() {
        return "B渠道";
    }
}

2:通过工厂类来初始化短信渠道service
TestFactory.java

@Service
public class TestFactory {
    
    //用来存储所有的渠道
    private Map<String, TestInterface> serviceMap;

    /*注入:通过spring容器将所有实现 TestInterface 接口的类的实例注入到 serviceList 中*/
    @Autowired
    private List<TestInterface> serviceList;
    
    //初始化注解
    @PostConstruct
    public void init(){
        //判断集合是否为空
        if (CollectionUtils.isEmpty(serviceList)) {
            return;
        }
        //初始化
        serviceMap = new HashMap<String,TestInterface>(serviceList.size());
        
        for (TestInterface testInterface : serviceList) {
            String typeName = testInterface.getType();
            if(serviceMap.get(typeName) != null){
                throw new RuntimeException("类型重复");
            }
            serviceMap.put(typeName, testInterface);
        }
        
    }
    //根据输入的渠道类型获取对应的渠道发送类
    public TestInterface getService(String typeName){
        return serviceMap.get(typeName);
    }  
}

3.在controller中调用不同短信渠道的接口。

@RestController
public class TestController {
    @Autowired
    private TestFactory testFactory;
    
    @RequestMapping("test01")
    public String test01(String typeName,String phone,String content){
        TestInterface service = testFactory.getService(typeName);
        service.send(phone, content);
        return "发送成功";
    }
    
}

这样TestController 类非常简洁,把“if else"干掉了, 如果我要增加一个短信渠道C,无需再次更改
TestController 类。 只需要增加一个类 TestImpl03 实现 TestInface
接口, 并实现自己的逻辑即可。

代码运行步骤:
1:Spring初始化的时候,因为工厂类TestFactory 有@Service注解,会将工厂类注册为Bean,同时
因为工厂类有 @PostConstruct 注解,会进行初始化操作。初始化的时候会将所有的渠道,全部存储到Map集合中,K=渠道名称,V=渠道对应的实现类。

2:Controller得到用户请求,会根据请求的类型调用工厂类的方法 getService(String typeName) ,得到对应的渠道实现类,同时调用实现类的方法,完成发送的逻辑。

3:运行完毕。

请大家支持一下兄弟, 点个赞,不要白嫖了。。。

你可能感兴趣的:(java,Spring)