设计模式——策略模式优化多场景登录

1,038 阅读2分钟

场景引入

策略模式主要解决的是if/else带来的一个代码臃肿问题。它的主要思想就是针对一个功能,有多种实现方式,并可以根据不同的条件去选择合适的方式。例如,通常一个平台会有多种登录方式,账号密码、手机号验证码、第三方平台等。这时,我们就可以使用策略模式,根据其登录类型来调用其对应的登录方法实现。

优点

  • 避免多重条件判断
  • 扩展性强
  • 算法能够自由切换

具体实现

创建登录通用接口

/**
 * @description: 登录通用接口
 * @author: guod
 * @date: 2022-06-27 09:55
 */
public interface TokenGranterStrategy {

    /**
     * 登录方法
     * @param loginParam
     * @return
     */
    AuthUserInfo grant(LoginParams loginParam);
}

创建登录抽象类,主要用于实现一些通用方法

/**
 * @description: 登录抽象类
 * @author: guod
 * @date: 2022-06-27 09:56
 */
@Slf4j
@Component
public abstract class AbstractTokenGranter implements TokenGranterStrategy{

    /**
     * 请求的公共校验
     */
    protected void publicCheck() {
        log.info("publicCheck()");
    }

    /**
     * 查询账号并校验账号相关信息
     * @param loginParams
     * @return
     */
    protected AccountVo checkAccount(LoginParams loginParams) {
        log.info("checkAccount()");
        return null;
    }

    /**
     * 根据账号信息,生成token
     * @param accountVo
     * @return
     */
    protected AuthUserInfo createToken(AccountVo accountVo) {
        log.info("createToken()");
        return null;
    }
}

创建对应的实现类

账号密码登录:

/**
 * @description: 密码登陆
 * @author: guod
 * @date: 2022-06-27 10:04
 */
@Slf4j
@Component
public class PasswordStrategy extends AbstractTokenGranter {
    @Override
    public AuthUserInfo grant(LoginParams loginParam) {
        publicCheck();
        AccountVo accountVo = checkAccount(loginParam);
        createToken(accountVo);
        log.info("PasswordGranter");
        return null;
    }
}

第三方平登录:

/**
 * @description: 第三方平台登录
 * @author: guod
 * @date: 2022-06-27 10:06
 */
@Slf4j
@Component
public class OpenIdStrategy extends AbstractTokenGranter {
    @Override
    public AuthUserInfo grant(LoginParams loginParam) {
        publicCheck();
        AccountVo accountVo = checkAccount(loginParam);
        createToken(accountVo);
        log.info("OpenIdTokenGranter");
        return null;
    }
}

手机号登录:

/**
 * @description: 手机号码登陆
 * @author: guod
 * @date: 2022-06-27 10:05
 */
@Slf4j
@Component
public class MobileStrategy extends AbstractTokenGranter {
    @Override
    public AuthUserInfo grant(LoginParams loginParam) {
        publicCheck();
        AccountVo accountVo = checkAccount(loginParam);
        createToken(accountVo);
        log.info("MobileTokenGranter");
        return null;
    }
}

创建对应的工厂类

/**
 * @description:
 * @author: guod
 * @date: 2022-06-27 10:14
 */
@Component
public class TokenGranterHolder {

    private final Map<String, TokenGranterStrategy> granterMap = new ConcurrentHashMap<>();

    public TokenGranterHolder(Map<String, TokenGranterStrategy> granterMap) {
        this.granterMap.putAll(granterMap);
    }


    /**
     * 根据登陆类型获取具体的处理类
     * @param grantType
     * @return
     */
    public TokenGranterStrategy getGranter(String grantType) {
        TokenGranterStrategy tokenGranterStrategy = granterMap.get(grantType);
        Optional.ofNullable(tokenGranterStrategy).orElseThrow(() -> new BizException("不存在该登陆类型"));
        return tokenGranterStrategy;
    }
}

登录类型枚举

/**
 * @description: 登录类型枚举类
 * @author: guod
 * @date: 2022-06-27 10:09
 */
@AllArgsConstructor
public enum GrantTypeEnum {

    PASSWORD("password", "passwordStrategy"),
    MOBILE("mobile", "mobileStrategy"),
    OPENID("openId", "openIdStrategy");

    @Getter
    private final String type;
    @Getter
    private final String value;

    public static String getValueByType(String type) {
        for (GrantTypeEnum grantTypeEnum : values()) {
            if (grantTypeEnum.getType().equals(type)) {
                return grantTypeEnum.getValue();
            }
        }
        return null;
    }
}

认证成功返回用户相关信息

/**
 * @description: 认证成功返回用户相关信息
 * @author: guod
 * @date: 2022-06-27 10:09
 */
@Data
public class AuthUserInfo implements Serializable {
    private static final long serialVersionUID = -1L;
    /**
     * 对应登录身份的id
     */
    private Long identityId;
    /**
     * 令牌
     */
    private String token;
    /**
     * 刷新令牌
     */
    private String refreshToken;
    /**
     * 过期时间(秒)
     */
    private long expire;
    /**
     * 到期时间
     */
    private LocalDateTime expiration;

}

最后验证下

/**
 * @description:
 * @author: zyk
 * @date: 2022-06-27 11:01
 */
@SpringBootTest
@Slf4j
public class StrategyTest {

    @Autowired
    private TokenGranterHolder tokenGranterHolder;

    @Test
    public void test() {
        String grantType = GrantTypeEnum.getValueByType("password");
        TokenGranterStrategy tokenGranterStrategy = tokenGranterHolder.getGranter(grantType);
        AuthUserInfo authUserInfo = tokenGranterStrategy.grant(new LoginParams());
    }
}

1656299492438.jpg