JAVA设计模式-行为型-策略模式

本文详细介绍了策略模式的概念和应用场景,通过一个真实的发送短信验证码的案例展示了如何使用策略模式和简单工厂模式优化大量if…else分支,以及如何进一步结合JAVA8的Function函数进行代码简化,以实现更灵活的扩展和维护。
摘要由CSDN通过智能技术生成


一、什么是策略模式

官方定义:
策略模式主要是针对一组算法,将每个算法封装到具有共同接口的独立类中,使得他们可以互相替换.

个人理解:
策略模式就是将原先的if…else判断给封装起来了,使得整体系统更为流畅以及更加容易扩展.

二、为什么要使用策略模式

先看 [代码示例-01] 实现发送短信验证码的需求
这是一个真实的代码案例,从案例中可以看出,发送短信验证码需要根据不同的场景去做对应的业务处理(其实就是各种判断),在初期开发的时候使用if…else分支是比较合理的,因为开始时只有几个场景需要发送短信,但是随着需求的迭代,后期一直在新增场景,导致需要一直增加if分支,最终使得代码比较混乱并且不容易维护.

下面使用[策略模式+简单工厂模式]去优化这部分代码,请看 [代码示例-02]
从优化过后的案例中可以看出,咱们使用策略模式将原来的一堆if…else给封装起来了,这样的话后面无论怎么新增场景,咱们只需要新增对应的策略实现类,然后将策略实现类保存至Map集合就好了,调用方的代码完全不需要变动.

这就是使用策略模式的好处,可以有效的减少代码中的if…else分支代码,能使代码更加的简洁易维护,并且从代码结构上来说更加清晰明了.

三、代码示例

1、代码示例-01

//请求类
public class SendSmsCodeForm extends CommonForm {

    @NotEmpty(message = "登录手机号不能为空")
    @ApiModelProperty(value = "登录手机号")
    private String phone;

    @NotNull(message = "短信验证码使用场景不能为空")
    @ApiModelProperty(value = "短信验证码使用场景")
    private TempCredentialScene scene;
}

//验证码场景枚举类
@Getter
@AllArgsConstructor
public enum TempCredentialScene {
    SMS_REG("SMS_REG", "短信注册验证码"),
    SMS_LOGIN("SMS_LOGIN", "短信登录验证码");
	//.........实际上还有很多场景
    private String code;
    private String name;
}

//具体业务类
public class ClassServiceImpl{

 //发送短信验证码
 public Result sendSmsCode(SendSmsCodeForm form) {
 
	 //.....业务前置逻辑
	 
	 if (TempCredentialScene.SMS_LOGIN == form.getScene()) {
		//...业务处理
	 }else if(TempCredentialScene.SMS_REG == form.getScene()){
		//...业务处理
	 }else if(TempCredentialScene.SMS_UPDATE_PHONE== form.getScene()){
	 	//...业务处理
	 }else{
	 	//.....实际上还有很多 if分支
	 }
	 
	 //......后续业务逻辑
	 
	 return Result.success();
	}
}

2、代码示例-02

//策略接口
public interface ISendSmsCodeVerifyStrategy {
	//发送验证码校验
    void sendSmsCodeVerify(SendSmsCodeForm form);
}

//具体策略实现-01
@Slf4j
@Service
public class SendSmsCodeRegisterVerify implements ISendSmsCodeVerifyStrategy {
    @Override
    public void sendSmsCodeVerify(SendSmsCodeForm form) {
        log.info("短信注册验证码验证逻辑...");
    }
}

//具体策略实现-02
@Service
@Slf4j
public class SendSmsCodeLoginVerify implements ISendSmsCodeVerifyStrategy {
    @Override
    public void sendSmsCodeVerify(SendSmsCodeForm form) {
        log.info("短信登录验证码验证逻辑...");
    }
}

//策略工厂-简单工厂模式(工厂使用单例)
public class SendSmsCodeVerifyStrategyFactory {

    private SendSmsCodeVerifyStrategyFactory() {
        init();
    }
	
	//使用静态内部类实现单例模式
    private static class Singleton {
        private static final SendSmsCodeVerifyStrategyFactory FACTORY = new SendSmsCodeVerifyStrategyFactory();
    }

    public static SendSmsCodeVerifyStrategyFactory getInstance() {
        return Singleton.FACTORY;
    }
	
	//定义Map集合保存所有的策略实现类
    private Map<TempCredentialScene, ISendSmsCodeVerifyStrategy> strategyMap;
	
	/*
	初始化方法,将策略实现类保存至Map集合
	SpringBeanUtils类是从Spring容器中获取Bean,因为使用了@Service注解,不能直接使用new去实例化对象
	*/
    private void init() {
        strategyMap = new HashMap<>(8);

        SendSmsCodeRegisterVerify sendSmsCodeRegisterVerify = SpringBeanUtils.getBean(SendSmsCodeRegisterVerify.class);
        strategyMap.put(TempCredentialScene.SMS_REG, sendSmsCodeRegisterVerify);

        SendSmsCodeLoginVerify sendSmsCodeLoginVerify = SpringBeanUtils.getBean(SendSmsCodeLoginVerify.class);
        strategyMap.put(TempCredentialScene.SMS_LOGIN, sendSmsCodeLoginVerify);
    }
	
	//根据场景获取具体的策略类
    public ISendSmsCodeVerifyStrategy get(TempCredentialScene scene) {
        ISendSmsCodeVerifyStrategy strategy = strategyMap.get(scene);
        if (null == strategy) {
            throw new RuntimeException("未知的策略...");
        }
        return strategy;
    }
}

//业务Service
@Service
public class SysTempCredentialServiceImpl implements ISysTempCredentialService {

    @Override
    public Result sendVerifyCodeSms(SendSmsCodeForm form) {
			
		//....前置逻辑处理		

		//获取策略类,调用策略方法
        ISendSmsCodeVerifyStrategy sendSmsCodeVerifyStrategy = SendSmsCodeVerifyStrategyFactory.getInstance().get(form.getScene());
        sendSmsCodeVerifyStrategy.sendSmsCodeVerify(form);
		
		//....后置逻辑处理
		return Result.success();
    }
}

四丶在实际开发中的应用

1、实际案例-01

首先根据 [代码示例-02] 咱们已经将原先的if…else相关的代码做了对应的封装,也满足了策略模式的要求,后期扩展也比较容易,但是小伙伴们也能发现,在使用了策略模式的情况下,每次新增一个策略就需要新增一个策略实现类,这样的话在场景(TempCredentialScene)非常多的情况下,就需要新增很多实现类,但是每个实现类中可能就几个方法而已,这样明显是不合理的,因为像这种业务场景是很常见的,如果都去新增策略实现类的话就很容易导致类膨胀,反而使得代码更加复杂了.

所以针对这种并不算很大的if…else分支的情况下,(类似支付方式:支付宝,微信,银联 这种分支就算大分支,因为他的实现逻辑肯定很复杂,这种的肯定还是需要新增策略实现类的),可以使用JAVA8的Function函数来更进一步的优化代码

使用策略模式+简单工厂模式+JAVA8-Function函数去优化 [代码示例-02] (此模式已经在项目中正式使用)

//优化策略工厂类
import java.util.function.Function;
public class SendSmsCodeVerifyStrategyFactory {

    private SendSmsCodeVerifyStrategyFactory() {
        init();
    }

    private static class Singleton {
        private static final SendSmsCodeVerifyStrategyFactory FACTORY = new SendSmsCodeVerifyStrategyFactory();
    }

    public static SendSmsCodeVerifyStrategyFactory getInstance() {
        return Singleton.FACTORY;
    }
	
	/*
	  这里的Map的Value修改为保存Function函数
	*/
      private Map<String, Consumer<SendSmsCodeForm>> strategyMap;

    private void init() {
        strategyMap = new HashMap<>(8);
		
		//获取SysTempCredentialServiceImpl中的方法,保存至Map集合中
        SysTempCredentialServiceImpl service = SpringBeanUtils.getBean(SysTempCredentialServiceImpl.class);
        strategyMap.put("SMS_REG", service::sendSmsCodeRegisterVerify);
        strategyMap.put("SMS_LOGIN", service::sendSmsCodeLoginVerify);
    }
	
	//执行函数
    public void accept(SendSmsCodeForm form) {
        Consumer<SendSmsCodeForm> consumer = strategyMap.get(form.getScene());
        if (null == consumer) {
            throw new RuntimeException("未知的策略");
        }
        consumer.accept(form);
    }
}

//业务Service
@Service
@Slf4j
public class SysTempCredentialServiceImpl implements ISysTempCredentialService {

    @Override
    public void sendVerifyCodeSms(SendSmsCodeForm form) {
        SendSmsCodeVerifyStrategyFactory.getInstance().accept(form);
    }

    public void sendSmsCodeRegisterVerify(SendSmsCodeForm form) {
        log.info("短信注册验证码验证逻辑...");
    }

    public void sendSmsCodeLoginVerify(SendSmsCodeForm form) {
        log.info("短信登录验证码验证逻辑...");
    }
}

从上述案例中可以看出,针对这种并不算很大的if…else分支,并不需要新增策略类,只需要新增对应的策略方法就好了(将原来的策略类变成策略方法),然后策略工厂由原来的保存策略类变成保存策略方法,最后根据Key去执行策略方法,

其实这样也算满足了开闭原则,因为后面新增场景的话只需要新增方法就好了,调用方的方法仍然不需要任何修改,这样既满足了减少代码中的if…else也解决了策略模式中类太多的问题.

五、总结

关于JAVA8的Function函数请同学自行百度
点击跳转百度文库中的JAVA-Function函数讲解

策略模式一般不会单独使用,通常是配合工厂模式使用,由一个变量(Key)去决定执行哪个具体的策略,合理的策略模式可以有效的减少代码中大量if…else,并且能够方便的扩展.

至此,策略模式就整理完毕辣~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值