这里使用登录做例子介绍如何实现登录的多种策略
上图是策略模式的基础模型。
context
Context上下文角色,也叫Context封装角色,起承上启下的作用,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化。
Strategy
策略角色,接口类,封装相同类型策略公共方法,具体策略实现算法
ConcreteStrategy
具体策略实现Strategy中的抽象方法,编写具体算法实现。
至此基本的策略模式就说完了,具体实现看下面在spring中我们如何实现这种策略模式来实现多种登录方式:
在spring中怎样实现Context 上下文角色
/*** 策略工厂,从spring上下文中提取策略* @author :Cai.ChangJun* @version 1.0.0* @Date : 2021/6/1*/
@Component
public class LoginStrategyFactory implements InitializingBean, ApplicationContextAware {private final Map<LoginType, LoginService> strategyMap = new ConcurrentHashMap<>();private ApplicationContext appContext;@Overridepublic void afterPropertiesSet() throws Exception {// 将 Spring 容器中所有的 LoginHandler 注册到 strategyMapappContext.getBeansOfType(LoginService.class).values().forEach(hander->strategyMap.put(hander.getLoginType(),hander));}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {appContext = applicationContext;}public LoginService getStrategy(LoginType loginType) {return strategyMap.get(loginType);}
}
首先实现ApplicationContextAware,在spring容器启动成功后将spring上下文注入到策略工厂中appContext
InitializingBean接口重写afterPropertiesSet 在bean初始化的时候去初始化strategyMap,从spring上下文中提取粗所有LoginService的实现类(具体策略)
定义策略角色(Strategy)
public interface LoginService {/*** 获取登录类型* @description:* @author Cai.ChangJun* @return: 登录类型* @version 1.0.0* @Date 2021/6/1 17:35*/LoginType getLoginType();/*** 登录并获得token一小时过期 缓存登录对象半小时过期* @author Cai.ChangJun* @param username : 用户名* @param password : 密码* @return UserDTO : 登录对象抽象* @version 1.0.0* @Date 2021/5/26 23:48*/UserDTO login(String username, String password);
}
具体策略实现
@Component
@Slf4j
public class PhoneChatLoginStrategy implements LoginService {@Overridepublic LoginType getLoginType() {return LoginType.PHONE;}@Overridepublic UserDTO login(String username, String password) {//TODO 未实现手机登录log.info("手机登录成功");return new UserDTO();}
}
@Component
@Slf4j
public class WeChatLoginStrategy implements LoginService {@Overridepublic LoginType getLoginType() {return LoginType.WE_CHAT;}@Overridepublic UserDTO login(String username, String password) {//TODO 未实现微信登录log.info("微信登录成功");return new UserDTO();}
}
每个策略我们提供了一个枚举,这样方便我们取具体策略。
public enum LoginType {QQ,WE_CHAT,PHONE;
}
我们这里写了两个登录策略,具体调用:
@RestController
@RequestMapping("/user")
@Slf4j
public class PublicUserController {@Autowiredprivate LoginStrategyFactory loginStrategyFactory;@PostMapping("/login")public Response<UserDTO> login(@RequestBody @Validated LoginParam loginParam) {log.info("用户登录:{}",loginParam.getUsername());LoginService strategy = loginStrategyFactory.getStrategy(loginParam.getLoginType());UserDTO login = strategy.login(loginParam.getUsername(), loginParam.getPassword());return new Response<>(login);}
}
这样我们就完成了在spring中使用策略模式完成多种登录策略。