策略模式以及在spring中进行扩展

策略模式

策略模式是一种行为型设计模式,它定义了一系列的算法,并将每一个算法封装起来,使它们可以互相替换。这样,算法的变化就可以独立于使用它的客户端。

策略模式的实现

场景:为了满足不同用户的登录需求,系统需要支持多种登录方式,包括用户名密码、手机号验证码及邮箱验证码登录。

在上面,我们可以看到以下元素体现了策略模式:

  1. ​​​接口 (LoginStrategy): 定义了所有支持的各种算法(即认证策略)的公共接口。在这里,login() 方法是所有策略都需要实现的行为。
  2. 具体策略类 (PasswordStrategy, EmailStrategy, PhoneAuthStrategy): 这些类实现了 AuthStrategy 接口,并提供了具体的实现。每一种认证方式都有自己的实现。
  3. 上下文 (AuthStrategyFactory): 负责管理策略对象,并将策略对象提供给客户端。在这个例子中,AuthStrategyFactory 包含了一个 Map<String, AuthStrategy>,用于存储不同类型的认证策略,并提供方法 getAuthStrategy() 来根据某种认证类型获取对应的策略实例。

具体的策略工厂代码实现

public class AuthStrategySingleFactory {

    private static final EnumMap<AuthEnumType,AuthStrategy> authStrategyMap = 
                new EnumMap<>(AuthEnumType.class);

    static {
        authStrategyMap.put(AuthEnumType.PHONE,new SmsAuthStrategy());
        authStrategyMap.put(AuthEnumType.PASSWORD,new PasswordAuthStrategy());
        authStrategyMap.put(AuthEnumType.EMAIL, new EmailAuthStrategy());
    }

    public static AuthStrategy getAuthStrategy(AuthEnumType authEnumType) {
        return authStrategyMap.get(authEnumType);
    }

}

以上代码仍有不足的地方,当我们需要添加新的登录方式策略时,需要修改策略工厂中静态代码块的代码,违背了开闭原则。

如何避免呢?

Spring扩展ApplicationContextAware 

ApplicationContextAware 是一个接口,它允许任何实现了它的类访问到当前的ApplicationContext。这在某些情况下非常有用,比如当一个类需要直接与 Spring 容器交互时。

解决方案

  1. 使用自定义自定义注解,用户表示具体策略类
  2. 实现ApplicationContextAware接口,便于访问Spring上下文
  3. 通过ApplicationContext.getBeanWithAnnotation()方法找到带有标签的类,并构建LoginStrategy映射

代码实现

@Component
public class AuthStrategyAnnotationParseFactory implements ApplicationContextAware {

    private ApplicationContext applicationContext;
    private final EnumMap<AuthEnumType,AuthStrategy> authEnumTypeAuthStrategyEnumMap = new EnumMap<>(AuthEnumType.class);

    
    public AuthStrategy getAuthStrategy(AuthEnumType authEnumType) {
        EnumMap<AuthEnumType, AuthStrategy> authEnumTypeAuthStrategyEnumMap1 = assembleAuthStrategy();
        AuthStrategy authStrategy = authEnumTypeAuthStrategyEnumMap1.get(authEnumType);
        if (authStrategy == null) {
            throw new UnsupportedOperationException(String.format("input type is %s , not null", authEnumType.getValue()));
        }
        return authStrategy;
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * 构建AuthStrategy映射
     * @return
     */
    public EnumMap<AuthEnumType,AuthStrategy> assembleAuthStrategy() {
        if (CollUtil.isEmpty(authEnumTypeAuthStrategyEnumMap)){
            Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(Auth.class);
            for (Object bean: beansWithAnnotation.values()) {
                if (bean instanceof AuthStrategy){
                    Auth annotation = bean.getClass().getAnnotation(Auth.class);
                    String description = annotation.description();
                    authEnumTypeAuthStrategyEnumMap.put(AuthEnumType.fromTypeName(description), (AuthStrategy) bean);
                }
            }
        }
        return authEnumTypeAuthStrategyEnumMap;
    }

}

实现在运行时动态地创建和注入新的具体策略类的方法还有很多,比如使用自定义@EnableXXXXX的方式配合,FactoryBean和ImportBeanDefinitionRegister进行动态注入

如果还有其他方法可以在发在评论区上一起学习进步!

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值