如何处理复杂的业务逻辑
在实际的业务开发当中,经常会遇到复杂的业务逻辑,可能实现出来的代码并没有什么问题,但是代码的可读性很差。
那么在实际开发中如何避免大面积的 if-else 代码块的问题?
补充说明一点,不是说 if-else 不好,而是多层嵌套的 if-else 导致代码可读性差、维护成本高等问题。
拆分逻辑单元最小化
把业务代码拆分成多段逻辑,提取通用的代码块,核心思想就是逻辑单元最小化,然后合并逻辑单元。
逻辑封装到枚举类中
利用“枚举”来优化复杂的多重业务判断代码,将业务中的逻辑封装到枚举类中。
public enum TimeEnum {
AM("am", "上午") {
@Override
public void setCity(TestCodeData data) {
}
},
PM("pm", "下午") {
@Override
public void setCity(TestCodeData data) {
}
},
DAY("day", "全天") {
@Override
public void setCity(TestCodeData data) {
}
};
public abstract void setCity(TestCodeData data);
private String code;
private String desc;
TimeEnum(String code, String desc) {
this.code = code;
this.desc = desc;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
// 使用方式
TimeEnum.AM.setCity(data); // 固定code:am
TimeEnum.valueOf("am").setCity(data); // 动态传入code:am
利用函数式接口优化
业务场景描述:比如让你做一个简单的营销拉新活动,这个活动投放到不同的渠道,不同渠道过来的用户奖励不一样。
假设在头条、微信等渠道都投放了该活动。此时你的代码可能会写出如下形式:
@RestController
@RequestMapping("/activity")
public class ActivityController {
@Resource
private AwardService awardService;
@PostMapping("/reward")
public void reward(String userId, String source) {
if ("toutiao".equals(source)) {
awardService.toutiaoReward(userId);
} else if ("wx".equals(source)) {
awardService.wxReward(userId);
}
}
}
@Service
public class AwardService {
private static final Logger log = LoggerFactory.getLogger(AwardService.class);
public Boolean toutiaoReward(String userId) {
log.info("头条渠道用户{}奖励50元红包!", userId);
return Boolean.TRUE;
}
public Boolean wxReward(String userId) {
log.info("微信渠道用户{}奖励100元红包!", userId);
return Boolean.TRUE;
}
}
看完这段代码,逻辑上是没有什么问题的。但它有一个隐藏的缺陷,如果后期又增加很多渠道的时候,你该怎么办?继续 else if 吗?
我们可以利用函数式接口优化,当然设计模式也可以优化。这里我只是举例使用一下函数式接口的使用方式。
@RestController
@RequestMapping("/activity")
public class ActivityController {
@Resource
private AwardService awardService;
@PostMapping("/reward")
public void reward(String userId, String source) {
awardService.getRewardResult(userId, source);
}
}
@Service
public class AwardService {
private static final Logger log = LoggerFactory.getLogger(AwardService.class);
private Map<String, BiFunction<String, String, Boolean>> sourceMap = new HashMap<>();
@PostConstruct
private void dispatcher() {
sourceMap.put("wx", (userId, source) -> this.wxReward(userId));
sourceMap.put("toutiao", (userId, source) -> this.toutiaoReward(userId));
}
public Boolean getRewardResult(String userId, String source) {
BiFunction<String, String, Boolean> result = sourceMap.get(source);
if (null != result) {
return result.apply(userId, source);
}
return Boolean.FALSE;
}
private Boolean toutiaoReward(String userId) {
log.info("头条渠道用户{}奖励50元红包!", userId);
return Boolean.TRUE;
}
private Boolean wxReward(String userId) {
log.info("微信渠道用户{}奖励100元红包!", userId);
return Boolean.TRUE;
}
}
针对一些复杂的业务场景,业务参数很多时,可以利用@FunctionalInterface 自定义函数式接口来满足你的业务需求,使用原理和本例并无差别。
工厂模式+抽象类
还是以上面的营销拉新活动为例来说明如何使用。
定义抽象业务接口:
public abstract class AwardAbstract {
public abstract Boolean award(String userId);
}
定义具体业务实现类:
// 头条渠道发放奖励业务
public class TouTiaoAwardService extends AwardAbstract {
@Override
public Boolean award(String userId) {
log.info("头条渠道用户{}奖励50元红包!", userId);
return Boolean.TRUE;
}
}
// 微信渠道发放奖励业务
public class WeChatAwardService extends AwardAbstract {
@Override
public Boolean award(String userId) {
log.info("微信渠道用户{}奖励100元红包!", userId);
return Boolean.TRUE;
}
}
利用工厂模式获取实例对象:
public class AwardFactory {
public static AwardAbstract getAwardInstance(String source) {
if ("toutiao".equals(source)) {
return new TouTiaoAwardService();
} else if ("wx".equals(source)) {
return new WeChatAwardService();
}
return null;
}
}
业务入口根据不同渠道执行不同的发放逻辑:
@PostMapping("/reward")
public void reward(String userId, String source) {
AwardAbstract instance = AwardFactory.getAwardInstance(source);
if (null != instance) {
instance.award(userId);
}
}
策略模式
还是以营销拉新为业务场景来说明
定义策略业务接口:
/**
* 策略业务接口
*/
public interface AwardStrategy {
/**
* 奖励发放接口
*/
Boolean award(String userId);
}
定义具体业务实现类:
@Service("toutiao")
public class TouTiaoAwardService implements AwardStrategy {
/**
* 头条渠道发放奖励业务
*/
@Override
public Boolean award(String userId) {
log.info("头条渠道用户{}奖励50元红包!", userId);
return Boolean.TRUE;
}
}
@Service("wx")
public class WeChatAwardService implements AwardStrategy {
/**
* 微信渠道发放奖励业务
*/
@Override
public Boolean award(String userId) {
log.info("微信渠道用户{}奖励100元红包!", userId);
return Boolean.TRUE;
}
}
业务入口根据不同渠道执行不同的发放逻辑:
@Autowired
private ApplicationContext applicationContext;
@GetMapping("award")
public void award(@RequestParam("type") String type, @RequestParam("userId") String userId) {
AwardStrategy service = applicationContext.getBean(type, AwardStrategy.class);
service.award(userId);
}
策略模式+模板方法+工厂模式+单例模式
还是以营销拉新为业务场景来说明,这个业务流程再增加一些复杂度,比如发放奖励之前要进行身份验证、风控验证等一些列的校验,此时你的业务流程该如何实现更清晰简洁呢?
定义业务策略接口:
/** 策略业务接口 */
public interface AwardStrategy {
/**
* 奖励发放接口
*/
Map<String, Boolean> awardStrategy(String userId);
/**
* 获取策略标识,即不同渠道的来源标识
*/
String getSource();
}
定义奖励发放模板流程:
public abstract class BaseAwardTemplate {
private static final Logger log = LoggerFactory.getLogger(BaseAwardTemplate.class);
//奖励发放模板方法
public Boolean awardTemplate(String userId) {
this.authentication(userId);
this.risk(userId);
return this.awardRecord(userId);
}
//身份验证
protected void authentication(String userId) {
log.info("{} 执行身份验证!", userId);
}
//风控
protected void risk(String userId) {
log.info("{} 执行风控校验!", userId);
}
//执行奖励发放
protected abstract Boolean awardRecord(String userId);
}
实现不同渠道的奖励业务:
@Slf4j
@Service
public class ToutiaoAwardStrategyService extends BaseAwardTemplate implements AwardStrategy {
/**
* 奖励发放接口
*/
@Override
public Boolean awardStrategy(String userId) {
return super.awardTemplate(userId);
}
@Override
public String getSource() {
return "toutiao";
}
/**
* 具体的业务奖励发放实现
*/
@Override
protected Boolean awardRecord(String userId) {
log.info("头条渠道用户{}奖励50元红包!", userId);
return Boolean.TRUE;
}
}
@Slf4j
@Service
public class WeChatAwardStrategyService extends BaseAwardTemplate implements AwardStrategy {
/**
* 奖励发放接口
*/
@Override
public Boolean awardStrategy(String userId) {
return super.awardTemplate(userId);
}
@Override
public String getSource() {
return "wx";
}
/***
* 具体的业务奖励发放实现
*/
@Override
protected Boolean awardRecord(String userId) {
log.info("微信渠道用户{}奖励100元红包!", userId);
return Boolean.TRUE;
}
}
定义工厂方法,对外统一暴露业务调用入口:
@Component
public class AwardStrategyFactory implements ApplicationContextAware {
private final static Map<String, AwardStrategy> MAP = new HashMap<>();
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Map<String, AwardStrategy> beanTypeMap = applicationContext.getBeansOfType(AwardStrategy.class);
beanTypeMap.values().forEach(strategyObj -> MAP.put(strategyObj.getSource(), strategyObj));
}
/**
* 对外统一暴露的工厂方法
*/
public Boolean getAwardResult(String userId, String source) {
AwardStrategy strategy = MAP.get(source);
if (Objects.isNull(strategy)) {
throw new RuntimeException("渠道异常!");
}
return strategy.awardStrategy(userId);
}
/**
* 静态内部类创建单例工厂对象
*/
private static class CreateFactorySingleton {
private static AwardStrategyFactory factory = new AwardStrategyFactory();
}
public static AwardStrategyFactory getInstance() {
return CreateFactorySingleton.factory;
}
}
业务入口方法:
@RestController
@RequestMapping("/activity")
public class ActivityController {
@PostMapping("/reward")
public void reward(String userId, String source) {
AwardStrategyFactory.getInstance().getAwardResult(userId, source);
}
}
总结寄语
设计模式对于 if-else 的优化,个人觉得有些重,但是也是一种优化方式。
设计模式适合使用在大的业务流程和场景中使用,针对代码块中的 if-else 逻辑优化不推荐使用。
不论使用那种技巧,首先是我们在业务代码开发过程中一定要多思考,将复杂的业务逻辑能通过简洁的代码表现出来,这才是你的核心能力之一,而不是一个 curd boy。
标签:Java,String,class,userId,优雅,Boolean,拆分,return,public From: https://www.cnblogs.com/zhaojinhui/p/16737319.html