type
status
date
slug
summary
tags
category
icon
password
一、定义

装饰器模式:初看上图感觉装饰器模式有点像俄罗斯套娃、某众汽车,而装饰器的核心就是在不改变原有类的基础上给类新增功能。不改变原有类,可能有的小伙伴会想到继承、AOP切面。可以避免继承导致的子类过多,
二、示例:
模拟场景:
例如,公司内部的sso单点登录已经提供了实现类,并有一套固定的校验体系。现在,因为公司业务扩张需要新增校验规则,同时还要保证原有的功能不被破坏。这时,我们可以考虑使用装饰器模式,扩充原有的单点登录功能。

基础设计
要想实现拦截的功能,就必须实现此接口
HandlerInterceptor
package com.qf.design.structure.decorate.basic; public interface HandlerInterceptor { /** * prehandler方法拦截,需要被实现 */ boolean preHandler(String request,String response,Object handler); }
父类的基础拦截功能:
SsoInterceptor
package com.qf.design.structure.decorate.basic; public class SsoInterceptor implements HandlerInterceptor{ /** * 父类的基础拦截功能 * @param request * @param response * @param handler * @return */ @Override public boolean preHandler(String request, String response, Object handler) { //模拟获取cookie String substring = request.substring(1, 8); //是否拦截 return substring.equals("success"); } }
传统的编码方式
重复书写父类实习代码,一旦父类的类变化了,又需要新写子类继承
package com.qf.design.structure.decorate.tradition; import com.qf.design.structure.decorate.basic.SsoInterceptor; import java.util.HashMap; import java.util.Map; public class LoginSsoDecoder extends SsoInterceptor { public LoginSsoDecoder(){} private static Map<String,String> authMap=new HashMap<>(); static { authMap.put("huahua", "queryUserInfo"); authMap.put("doudou", "queryUserInfo"); } @Override public boolean preHandler(String request, String response, Object handler) { //模拟获取cookie String substring = request.substring(1, 8); //是否拦截 boolean success = substring.equals("success"); if (!success) return false; //自己需要拓展的拦截逻辑 String userId = request.substring(9); String method = authMap.get(userId); // 模拟方法校验 return "queryUserInfo".equals(method); } }
测试:
ApiTest
package com.qf.design.structure.decorate.tradition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ApiTest { private static Logger logger= LoggerFactory.getLogger(ApiTest.class); public static void main(String[] args) { LoginSsoDecoder loginSsoDecoder=new LoginSsoDecoder(); String request="ssuccessshuahuas"; boolean result = loginSsoDecoder.preHandler(request, "response", ""); logger.info("登录校验:"+request+(result?"通过":"失败")); } }
装饰器模式设计
作为中转站,接受传递的子类,并调用子类的preHandler
被继承的接⼝可以通过构造函数传递其实现类
package com.qf.design.structure.decorate.design; import com.qf.design.structure.decorate.basic.HandlerInterceptor; public abstract class SsoDecoder implements HandlerInterceptor { private HandlerInterceptor handlerInterceptor; public SsoDecoder(HandlerInterceptor handlerInterceptor){ this.handlerInterceptor=handlerInterceptor; } @Override public boolean preHandler(String request, String response, Object handler) { return handlerInterceptor.preHandler(request,response,handler); } }
package com.qf.design.structure.decorate.design; import com.qf.design.structure.decorate.basic.HandlerInterceptor; import java.util.HashMap; import java.util.Map; public class LoginSsoDecoder extends SsoDecoder{ private static Map<String,String> authMap=new HashMap<>(); static { authMap.put("huahua", "queryUserInfo"); authMap.put("doudou", "queryUserInfo"); } public LoginSsoDecoder(HandlerInterceptor handlerInterceptor){ super(handlerInterceptor); } @Override public boolean preHandler(String request, String response, Object handler) { //父类的拦截 boolean result = super.preHandler(request, response, handler); if (!result) return false; //自己需要拓展的拦截逻辑 String userId = request.substring(9); String method = authMap.get(userId); // 模拟方法校验 return "queryUserInfo".equals(method); } }
测试:
ApiTest
package com.qf.design.structure.decorate.design; import com.qf.design.structure.decorate.basic.SsoInterceptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ApiTest { private static Logger logger= LoggerFactory.getLogger(ApiTest.class); public static void main(String[] args) { LoginSsoDecoder loginSsoDecoder = new LoginSsoDecoder(new SsoInterceptor()); String request="ssuccessshuahua"; boolean result = loginSsoDecoder.preHandler(request, "response", ""); logger.info("登录校验:"+request+(result?"通过":"失败")); } }
UML关系图

总结:
使⽤装饰器模式满⾜单⼀职责原则,你可以在⾃⼰的装饰类中完成功能逻辑的扩展,⽽不影响主类,同时可以按需在运⾏时添加和删除这部分逻辑。另外装饰器模式与继承⽗类重写⽅法,在某些时候需要需选择,并不⼀定某⼀个就是最好。
装饰器实现的重点是对抽象类继承接⼝⽅式的使⽤,同时设定被继承的接⼝可以通过构造函数传递其实现类,由此增加扩展性并重写⽅法⾥可以实现此部分⽗类实现的功能。假设基础主类发生了重大修改(改了类名或者新写),我们只需要传递最终所需要的主类
- 作者:程序员小舟
- 链接:https://codezhou.top/article/JAVA%E3%80%90%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E3%80%91%E8%A3%85%E9%A5%B0%E5%99%A8%E6%A8%A1%E5%BC%8F
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章