目录
定义
装饰器的核⼼就是再不改原有类的基础上给类新增功能。不改变原有类,使⽤装饰器模式会是另外⼀种思路更为灵活,可以避免继承导致的⼦类过多。
模拟⼀个单点登录功能扩充
⼀般在业务开发的初期,往往内部的ERP使⽤只需要判断账户验证即可,验证通过后即可访问ERP的所
有资源。但随着业务的不断发展,团队⾥开始出现专⻔的运营⼈员、营销⼈员、数据⼈员,每个⼈员对
于ERP的使⽤需求不同,有些需要创建活动,有些只是查看数据。同时为了保证数据的安全性,不会让
每个⽤户都有最⾼的权限。 那么以往使⽤的 SSO 是⼀个组件化通⽤的服务,不能在⾥⾯添加需要的⽤户访问验证功能。这个时候我们就可以使⽤装饰器模式,扩充原有的单点登录服务。但同时也保证原有功能不受破坏,可以继续使⽤。
模拟Spring的HandlerInterceptor
public interface HandlerInterceptor {
boolean preHandle(String request, String response, Object handler);
}
实际的单点登录开发会基于; org.springframework.web.servlet.HandlerInterceptor 实现。
模拟单点登录功能
public class SsoInterceptor implements HandlerInterceptor{
public boolean preHandle(String request, String response, Object handler) {
// 模拟获取cookie
String ticket = request.substring(1, 8);
// 模拟校验
return ticket.equals("success");
}
}
代码实现
抽象类装饰⻆⾊
public abstract class SsoDecorator implements HandlerInterceptor {
private HandlerInterceptor handlerInterceptor;
private SsoDecorator(){}
public SsoDecorator(HandlerInterceptor handlerInterceptor) {
this.handlerInterceptor = handlerInterceptor;
}
public boolean preHandle(String request, String response, Object handler) {
return handlerInterceptor.preHandle(request, response, handler);
}
}
在装饰类中有两个点的地⽅是;1)继承了处理接⼝、2)提供了构造函数、3)覆盖了⽅法 preHandle 。以上三个点是装饰器模式的核⼼处理部分,这样可以踢掉对⼦类继承的⽅式实现逻辑功能扩展。
装饰⻆⾊逻辑实现
public class LoginSsoDecorator extends SsoDecorator {
private Logger logger = LoggerFactory.getLogger(LoginSsoDecorator.class);
private static Map<String, String> authMap = new ConcurrentHashMap<String, String>();
static {
authMap.put("huahua", "queryUserInfo");
authMap.put("doudou", "queryUserInfo");
}
public LoginSsoDecorator(HandlerInterceptor handlerInterceptor) {
super(handlerInterceptor);
}
@Override
public boolean preHandle(String request, String response, Object handler) {
boolean success = super.preHandle(request, response, handler);
if (!success) return false;
String userId = request.substring(8);
String method = authMap.get(userId);
logger.info("模拟单点登录⽅法访问拦截校验:{} {}", userId, method);
// 模拟⽅法校验
return "queryUserInfo".equals(method);
}
}
测试验证
@Test
public void test_LoginSsoDecorator() {
LoginSsoDecorator ssoDecorator = new LoginSsoDecorator(new SsoInterceptor());
String request = "1successhuahua";
boolean success = ssoDecorator.preHandle(request, "ewcdqwt40liuiu", "t");
System.out.println("登录校验:" + request + (success ? " 放⾏" : " 拦截"));
}