原创 吴就业 125 0 2020-09-13
本文为博主原创文章,未经博主允许不得转载。
本文链接:https://wujiuye.com/article/aada543bf1274549a680ed464eebc96b
作者:吴就业
链接:https://wujiuye.com/article/aada543bf1274549a680ed464eebc96b
来源:吴就业的网络日记
本文为博主原创文章,未经博主允许不得转载。
本篇文章写于2020年09月13日,从公众号|掘金|CSDN手工同步过来(博客搬家),本篇为原创文章。
23种设计模式属于结构型模式,而mvc模式等属于架构型模式。本篇要讨论的设计模式指的是结构型设计模式。
有时候我们在项目中使用设计模式也不能准确的说出自己使用的是哪种设计模式,这就是设计模式难学的地方,总的来说,就是偏理论、难理解。
设计模式是前人总结出的一套高效编程方式,使用设计模式能够为功能模块提供更好扩展性,为代码带来更好的可读性,一定程度上也是对代码性能方面的调优。
当我们清楚的知道使用设计模式的目的在于此之后,也就不用再去生搬硬套的使用设计模式了。在实际开发中,我们需要结合实际场景考虑使用何种设计模式,即便使用同一种设计模式,在不同的场景下也有不同的用法。
23种设计模式中,每一种都可以稍作改动以迎合实际使用场景,并且这些设计模式不仅可以单独使用,有时候也可以组合使用,如组合模式与策略模式的组合使用。
本篇将从笔者的角度,以常用的、比较容易搞混的设计模式为例,分享笔者对设计模式及其运用的理解,仅供参考。
参考维基百科:责任链模式包含了一些命令对象和一系列的处理对象,每一个处理对象决定它能处理哪些命令对象,它也知道如何将它不能处理的命令对象传递给该链中的下一个处理对象。该模式还描述了往该处理链的末尾添加新的处理对象的方法。
责任链模式我们并不陌生,Netty中的ChannelHandler、Sentinel的Slot都有运用责任链模式。
Netty中的ChannelHandler责任链模式:
> (图片来源:《Netty 中的 handler 和 ChannelPipeline 分析》https://www.cnblogs.com/rickiyang/p/12686593.html)
Sentinel中的Slot责任链模式:
(图片来源:《深入理解Sentinel》https://gitbook.cn/gitchat/column/5f34b38305cd3d35a3b01d4a)
举例Netty与Sentinel的目的也在于这两者在运用上存在些许区别,前者实现的是双向传递的责任链,后者则是单向传递。两者也存在共同点,都是使用链表将一系列处理对象连成责任链。
除了使用单向或者双向链表方式实现责任链调用模式,还可以使用集合实现,将处理对象按顺序放入集合中,通过遍历集合方式调用。
在23种设计模式中,并没有对过滤器模式与拦截器模式单独定义,在wiki上也只是将这两者归类为结构型设计模式。
无论是过滤器模式还是拦截器模式,在实现上,两者都依赖责任链模式,因此,笔者将过滤器模式与拦截器模式看作是责任链模式的一种衍生模式,是责任链模式的一个变种,但不能使用等号。
过滤器模式是将所有过滤器对象构成链表,只要其中一个过滤器满足条件,那么后续的过滤器将不会被调用,命令最终可由该过滤器处理。
过滤器的过滤方法一般返回boolean值,表示过滤或不过滤,当过滤方法返回值类型为void时,表示过滤器在决定过滤当前命令后,必须对该命令作出响应以结束命令处理。
过滤器模式对过滤器的调用顺序并没有严格要求,是否要求顺序主要取决于具体的使用场景。
如需考虑优先级的黑白名单过滤器,顺序不同结果截然不同;
如Shiro使用过滤器模式实现的认证授权功能。
(Shiro框架过滤器模式)
拦截器模式与过滤器模式大致相同,常见与动态代理模式结合使用,拦截器可以拦截方法调用(请求)或者改变方法调用(请求)传递的参数。
参考维基百科:代理模式的目标是定义代理对象,该对象在客户端和实际主体之间操作,以控制对真实主体的访问,并在每次访问真实主题时执行必要的任务。
代理模式也分动态代理和静态代理,其中动态代理模式是使用最广、最多的代理模式。代理模式也是使用最多的设计模式之一。
参考维基百科:委托模式是软件设计模式中的一项基本技巧。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。
代理模式与委托模式到底哪里不同也是饱受争议。
在23种设计模式中并没有对委托模式单独定义,有人认为,委托模式只是代理模式的别称,也有人认为,委托并不一定要调用相同方法,也不需要实现相同接口,而代理是代理一个方法或者一个接口的所有方法。
从定义上来看,两者确实是不同的设计模式,对于上述两种观点,如果要论对错,笔者更认可后者。
笔者曾经使用C#开发windows应用程序使用比较多的是委托模式,如处理一个日记事件,当监听到日记时,委托一个类去将日记显示到前端控件上,委托者委托受托者将日记显示,两者之间并没有严格的约定。
> (c#写的聊天软件:M.Friend)
这是来自知乎的回答,可参考:委托,是委托人与受托人约定,由受托人处置委托人委托的事务的民事法律关系;代理是代理人在代理权限内,以被代理人的名义实施民事法律的行为。好像这样描述更难理解了。
参考维基百科:组合模式也叫复合模式,复合模式描述一组对象,这些对象与相同类型对象的单个实例处理的方式相同。复合的目的是将对象”组合”到树结构中,以表示部分整体层次结构。
通俗的理解,组合模式是将实现同一个接口的实例组合到一起,也可以将多个相同类型的组合组合到一起,构成一棵数。当外部调用这棵数的方法时,所有的叶子节点的方法都会被调用。
组合模式我们可能比较陌生,所以我们看一个实例来理解。
1、声明组合中的对象接口:组件(Component),并提供接口实现类(Leaf);
2、定义具有组件行为的组合类,存储组件、支持添加组件;
3、通过组合操作组合中的对象。
参考维基百科:策略模式指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。
组合模式与策略模式组合使用,在SpringBoot的web框架中非常常见,例如实现方法参数解析。
定义方法参数解析器(HandlerMethodArgumentResolver),HandlerMethodArgumentResolver即是策略模式中的策略接口(Strategy),也是组合模式中的组件(Component)。
组合模式将具有相同处理方式的对象组合到一起,也就是将所有方法参数解析器组合到一起。
策略模式根据方法参数的类型或者参数上的注解等选择一个能够解析该方法参数的解析器,由解析器从请求(数据包)中解析出方法参数。
HandlerMethodArgumentResolverComposite即是组合模式中的组合(Composite),也是策略模式中的Context。
RequestResponseBodyMethodProcessor负责解析被@ResponseBody注解注释的方法参数、PathVariableMethodArgumentResolver负载解析被@PathVariable注解注释的方法参数,这些都是组合模式中的叶子节点(Leaf),也是策略模式中的实体策略。
适配器模式的定义:适配器模式是使因接口不兼容而不能在一起工作的类能在一起工作,做法是将类自己的接口包裹在一个已存在的类中。
以实现支付结果回调失败定时重试为例,假设现有两种失败定时重试实现方案:
一种是支持使用cron表达式的失败定时重试;
另一种是支持自定义周期的失败定时重试,如间隔2秒、4秒、8秒…后重试。
使用适配器模式将两种方式组合到一起对外提供服务,并且做一些扩展。
对于外部调用者而言,只需要访问一个接口就能获得多种方式的支持,内部多种方式一起对外提供服务。
如何理解设计模式应当为适应不同场景作出改变?我们以封装json序列化和反序列化工具为例。
在实际项目中,我们可以使用gson、Jackson等框架实现Java对象的序列化与反序列化,但一般我们不会同时使用多个,也不会存在面对不同的业务使用不同框架的情况。相反的,一般我们只会选择其中一种,并且不会经常改变。
使用策略模式可以实现后期切换框架而不需要修改业务代码,但这种场景下,我们真的需要教科书式的实现策略模式吗。
最适合的方法应当是根据引入不同的框架决定使用哪种序列化策略,通过类加载实现“策略”,这种微妙的改变为封装的组件提供了更智能的策略。
例如,我们在项目中添加gson的依赖后,整个项目的序列化和反序列化工作都将由gson完成,而当我们把依赖gson改为依赖Jackson时,整个项目的序列化和反序列化工作都将自动切换到Jackson。
设计模式不应该被生搬硬套的使用,否则也就违背了使用设计模式的初衷。
声明:公众号、CSDN、掘金的曾用名:“Java艺术”,因此您可能看到一些早期的文章的图片有“Java艺术”的水印。
随着微服务的流行,很多公司也在逐渐的将单体架构项目重构为微服务项目,单体架构微服务化后也将面临更多的挑战。服务的调用错综复杂,如何保护自身不被其它服务打垮也是项目微服务化后重点需要考虑的问题。
Instrumentation之所以难驾驭,在于需要了解Java类加载机制以及字节码,一不小心就能遇到各种陌生的Exception。笔者在实现Java探针时就踩过不少坑,其中一类就是类加载相关的问题,也是本篇所要跟大家分享的。
我们基于Spring Cloud Gateway开发内部微服务网关,并结合注册中心实现自动服务发现路由。就在最近将项目部署测试环境的Kubernetes集群上时,发现路由失败。
订阅
订阅新文章发布通知吧,不错过精彩内容!
输入邮箱,提交后我们会给您发送一封邮件,您需点击邮件中的链接完成订阅设置。