统一用户登陆(二)基于注解实现策略模式(reflections与Holder模式)

一.问题的延续与解决思路

在这里插入图片描述
  我们发现在寻找策略类的时候,还是在根据loginType去判断使用什么策略,那么依然逃避不了IF,ElSE这样的代码。那我们此章采用注解的方式来解决这个问题。
  解决思路

  1. loginType与策略的关系为一一对应,那么我们可以将策略类使用注解标记,并且绑定一个loginType值。
  2. 通过反射我们识别到loginType与策略的关系,然后通过Spring来获取具体的策略的实例。

二.具体实现

1. 定义登陆方式的枚举


/**
 * 登陆方式
 */
public enum LoginType {

    ACCOUNT_PWD("1", "账号密码登陆"), 
    
    ACCOUNT_SMS("2", "账号+短信验证码登陆"), ;


    /**
     * 登陆方式
     */
    private String loginType;

    /**
     * 描述信息
     */
    private String loginDesc;

    LoginType(String loginType, String loginDesc) {
        this.loginType = loginType;
        this.loginDesc = loginDesc;
    }

    public String getLoginType() {
        return loginType;
    }

    public String getLoginDesc() {
        return loginDesc;
    }
}

2. 定义登陆策略注解

/**
 * 登陆策略注解
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginInstance {

    //登陆方式
    LoginType loginType();
}

3. 标记策略类

@Service
@LoginInstance(loginType = LoginType.ACCOUNT_PWD)
public class AccountSmsLogProcessor extends LoginTemplate

@Service
@LoginInstance(loginType = LoginType.ACCOUNT_PWD)
public class AccountPwdLogProcessor extends LoginTemplate

4.实现通过注解获取策略(reflections)
4.1 加入反射工具依赖

 implementation 'org.reflections:reflections:0.9.11'

4.2 增加注解解析


/**
 * 登陆工具类
 */
public class LoginTypeUtil{
    public static Map<String, String> map = new ConcurrentHashMap<String, String>();

    static {
        //反射工具包,指明扫描路径
        Reflections reflections = new Reflections("com.demo");
        //获取带LoginInstance注解的类
        Set<Class<?>> classList = reflections.getTypesAnnotatedWith(LoginInstance.class);
        for (Class classes : classList) {
            Annotation annotation = classes.getAnnotation(LoginInstance.class);
            if (annotation != null) {
                LoginInstance loginInstance = (LoginInstance) annotation;
                map.put(loginInstance.loginType().getLoginType(), normalizeFirstWord(classes.getSimpleName()));
            }
        }
    }

    /**
     * 首字母转为小写
     * @param name
     * @return
     */
    public static String normalizeFirstWord(String name) {
        if (name == null || name.length() == 0) {
            return name;
        }
        if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
                Character.isUpperCase(name.charAt(0))){
            return name;
        }
        char chars[] = name.toCharArray();
        chars[0] = Character.toLowerCase(chars[0]);
        return new String(chars);
    }

    /**
     * 通过loginType获取策略实例
     * @param loginType
     * @return
     */
    public static LoginAdapter getInstanceByLoginType(String loginType) {
        return (LoginAdapter)SpringBeanUtil.getBean(map.get(loginType));
    }
}

4.3 改造策略获取方式

@Component
public class LoginProcessor {

    /**
     * 根据loginType获取登录的策略
     * @param loginRo
     * @return
     */
    public LoginAdapter userLogin(LoginRo loginRo) {
        return LoginTypeUtil.getInstanceByLoginType(loginRo.getLoginType());
    }
}

4.4 测试登陆
在这里插入图片描述

5.实现通过注解获取策略(Spring,Holder)

5.1 编写HolderConfig

@Configuration
public class HolderConfig {

    @Bean
    public LoginProcessorHolder orderPayPostProcessorHolder(List<LoginAdapter> list){
        return new LoginProcessorHolder(list);
    }

}

5.2 编写策略装配

public class LoginProcessorHolder {

    private static final Map<String, Class> HOLDER = new HashMap<>();

    public LoginProcessorHolder(List<LoginAdapter> list) {
        if (list != null && list.size() > 0){
            for (LoginAdapter processAdapter : list) {
                LoginInstance processor = AnnotationUtils.findAnnotation(processAdapter.getClass(), LoginInstance.class);
                if (processor != null){
                    LoginType loginType = processor.loginType();
                    HOLDER.put(loginType.getLoginType(), processAdapter.getClass());
                }
            }
        }
    }

    public LoginAdapter getInstanceByLoginType(String loginType){
        Class adapter = HOLDER.get(loginType);
        return (LoginAdapter) SpringBeanUtil.getBean(adapter);
    }

}

5.3 修改策略获取方法

@Component
public class LoginProcessor {

    @Resource
    private LoginProcessorHolder loginProcessorHolder;

    /**
     * 根据loginType获取登录的策略
     * @param loginRo
     * @return
     */
    public LoginAdapter userLogin(LoginRo loginRo) {
        //return LoginTypeUtil.getInstanceByLoginType(loginRo.getLoginType());
        return loginProcessorHolder.getInstanceByLoginType(loginRo.getLoginType());
    }
}

这里使用了reflections以及Holder来解决策略实现类的获取,根据个人喜欢可以选择不同的模式,我更人更倾向于Holder模式。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值