做者:小傅哥
博客:https://bugstack.cnhtml
沉淀、分享、成长,让本身和他人都能有所收获!😄
对于代码你有编程感受吗
java
不少人写代码每每是没有编程感受的,也就是除了能够把功能按照固定的流程编写出流水式的代码外,很难去思考整套功能服务的扩展性和可维护性。尤为是在一些较大型的功能搭建上,比较缺失一些驾驭能力,从而致使最终的代码相对来讲不能作到尽善尽美。web
江洋大盗与江洋大偷
spring
两个本想描述同样的意思的词,只因一字只差就让人以为一个是好牛,一个好搞笑。每每咱们去开发编程写代码时也常常将一些不恰当的用法用于业务需求实现中,当却不能意识到。一方面是因为编码很少缺乏较大型项目的实践,另外一方面是不思进取的总在以完成需求为目标缺乏精益求精的工匠精神。编程
书历来不是看的而是用的
设计模式
在这个学习资料几乎爆炸的时代,甚至你能够轻易就获取几个T的视频,小手轻轻一点就收藏一堆文章,但却不多去看。学习的过程从不仅是简单的看一遍就能够,对于一些实操性的技术书籍,若是真的但愿学习到知识,那么必定是把这本书用起来而绝对不是看起来。安全
bugstack虫洞栈
,回复源码下载
获取(打开获取的连接,找到序号18)工程 | 描述 |
---|---|
itstack-demo-design-9-00 | 场景模拟工程;模拟单点登陆类 |
itstack-demo-design-9-01 | 使用一坨代码实现业务需求 |
itstack-demo-design-9-02 | 经过设计模式优化改造代码,产生对比性从而学习 |
初看上图感受装饰器模式有点像俄罗斯套娃、某众汽车🚕,而装饰器的核心就是再不改原有类的基础上给类新增功能。不改变原有类,可能有的小伙伴会想到继承、AOP切面,固然这些方式均可以实现,可是使用装饰器模式会是另一种思路更为灵活,能够避免继承致使的子类过多,也能够避免AOP带来的复杂性。微信
你熟悉的场景不少用到装饰器模式cookie
new BufferedReader(new FileReader(""));
,这段代码你是否熟悉,相信学习java开发到字节流、字符流、文件流的内容时都见到了这样的代码,一层嵌套一层,一层嵌套一层,字节流转字符流等等,而这样方式的使用就是装饰器模式的一种体现。并发
在本案例中咱们模拟一个单点登陆功能扩充的场景
通常在业务开发的初期,每每内部的ERP使用只须要判断帐户验证便可,验证经过后便可访问ERP的全部资源。但随着业务的不断发展,团队里开始出现专门的运营人员、营销人员、数据人员,每一个人员对于ERP的使用需求不一样,有些须要建立活动,有些只是查看数据。同时为了保证数据的安全性,不会让每一个用户都有最高的权限。
那么以往使用的SSO
是一个组件化通用的服务,不能在里面添加须要的用户访问验证功能。这个时候咱们就可使用装饰器模式,扩充原有的单点登陆服务。但同时也保证原有功能不受破坏,能够继续使用。
itstack-demo-design-9-00 └── src └── main └── java └── org.itstack.demo.design ├── HandlerInterceptor.java └── SsoInterceptor.java
HandlerInterceptor
,实现起接口功能SsoInterceptor
模拟的单点登陆拦截服务。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"); } }
HttpServletRequest request
对象中获取cookie
信息,解析ticket
值作校验。success
就认为是容许登陆。此场景大多数实现的方式都会采用继承类
继承类的实现方式也是一个比较通用的方式,经过继承后重写方法,并发将本身的逻辑覆盖进去。若是是一些简单的场景且不须要不断维护和扩展的,此类实现并不会有什么,也不会致使子类过多。
itstack-demo-design-9-01 └── src └── main └── java └── org.itstack.demo.design └── LoginSsoDecorator.java
LoginSsoDecorator
继承 SsoInterceptor
,重写方法功能。public class LoginSsoDecorator extends SsoInterceptor { private static Map<String, String> authMap = new ConcurrentHashMap<String, String>(); static { authMap.put("huahua", "queryUserInfo"); authMap.put("doudou", "queryUserInfo"); } @Override public boolean preHandle(String request, String response, Object handler) { // 模拟获取cookie String ticket = request.substring(1, 8); // 模拟校验 boolean success = ticket.equals("success"); if (!success) return false; String userId = request.substring(9); String method = authMap.get(userId); // 模拟方法校验 return "queryUserInfo".equals(method); } }
@Test public void test_LoginSsoDecorator() { LoginSsoDecorator ssoDecorator = new LoginSsoDecorator(); String request = "1successhuahua"; boolean success = ssoDecorator.preHandle(request, "ewcdqwt40liuiu", "t"); System.out.println("登陆校验:" + request + (success ? " 放行" : " 拦截")); }
登陆校验:1successhuahua 拦截 Process finished with exit code 0
接下来使用装饰器模式来进行代码优化,也算是一次很小的重构。
装饰器主要解决的是直接继承下因功能的不断横向扩展致使子类膨胀的问题,而是用装饰器模式后就会比直接继承显得更加灵活同时这样也就再也不须要考虑子类的维护。
在装饰器模式中有四个比较重要点抽象出来的点;
定义抽象接口
实现抽象接口,能够是一组
定义抽象类并继承接口中的方法,保证一致性
扩展装饰具体的实现逻辑
经过以上这四项来实现装饰器模式,主要核心内容会体如今抽象类的定义和实现上。
itstack-demo-design-9-02 └── src └── main └── java └── org.itstack.demo.design ├── LoginSsoDecorator.java └── SsoDecorator.java
装饰器模式模型结构
SsoDecorator
,这个类是一个抽象类主要完成了对接口HandlerInterceptor
继承。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); } }
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); } }
SsoDecorator
,那么如今就能够扩展方法;preHandle
preHandle
的实现中能够看到,这里只关心扩展部分的功能,同时不会影响原有类的核心服务,也不会由于使用继承方式而致使的多余子类,增长了总体的灵活性。@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 ? " 放行" : " 拦截")); }
new SsoInterceptor()
,传递给装饰器,让装饰器能够执行扩充的功能。23:50:50.796 [main] INFO o.i.demo.design.LoginSsoDecorator - 模拟单点登陆方法访问拦截校验:huahua queryUserInfo 登陆校验:1successhuahua 放行 Process finished with exit code 0
list
集合消息,但你又不但愿全部的代码类都去修改这部分逻辑。那么可使用装饰器模式进行适配list
集合,给使用者依然是for
循环后的单个消息。