写点什么

向 Spring 框架学习设计模式

  • 2022 年 7 月 01 日
  • 本文字数:3208 字

    阅读完需:约 11 分钟

引言

设计模式是大师们总结的编码范式,用于提升代码的扩展性以及优雅性。对于一个研发人员来说,能否写出一手让人点赞的代码,很大程度上取决于我们对于设计模式的落地使用。那么对于一些初学者来说,怎么才能以最快的方式来学习和理解设计模式呢?个人觉得比较好的方式是通过优秀的开源框架来进行学习,这些开源框架中大量使用了设计模式来进行功能扩展。本文主要分析下最常用的 Spring 框架中蕴含了哪些设计模式以及设计思想。


模板模式

顾名思义,模板模式就是根据制定的模板来创建实力对象的过程,可以这么理解,就是模版是一个印章,通过印章可以形成多个盖章。下面我们来看下 Spring 是如何使用模板模式的。


Spring 提供的数据库访问的模板类 JdbcTemplate,它就是使用了模板的设计模式。它对核心思想就是将业务流程固定化,比如数据库连接的获取,数据库连接的关闭等,然后将变化的部分交由子类或者回调函数实现。


public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
... @Nullable public <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action) throws DataAccessException { Assert.notNull(psc, "PreparedStatementCreator must not be null"); Assert.notNull(action, "Callback object must not be null"); if (this.logger.isDebugEnabled()) { String sql = getSql(psc); this.logger.debug("Executing prepared SQL statement" + (sql != null ? " [" + sql + "]" : "")); } //固化流程1:获取connection Connection con = DataSourceUtils.getConnection(this.obtainDataSource()); PreparedStatement ps = null;
Object var13; try { //固化流程2:获取PrepareStatement ps = psc.createPreparedStatement(con); this.applyStatementSettings(ps); T result = action.doInPreparedStatement(ps); this.handleWarnings((Statement)ps); var13 = result; } catch (SQLException var10) { if (psc instanceof ParameterDisposer) { ((ParameterDisposer)psc).cleanupParameters(); }
String sql = getSql(psc); psc = null; //固化流程3:关闭Statement JdbcUtils.closeStatement(ps); ps = null; //固化流程4:关闭Connection DataSourceUtils.releaseConnection(con, this.getDataSource()); con = null; throw this.translateException("PreparedStatementCallback", sql, var10); } finally { if (psc instanceof ParameterDisposer) { ((ParameterDisposer)psc).cleanupParameters(); }
JdbcUtils.closeStatement(ps); DataSourceUtils.releaseConnection(con, this.getDataSource()); }
return var13; }
...}
复制代码


观察者模式

我们都知道观察者模式在实际都工作中属于比较常用都设计模式。简单来说就是当一个对象当状态发生变化时,监视该对象的主体改变其行为的设计模式就是观察者模式。举个日常生活中的例子,比如你女朋友下班回家,我们就要观察女朋友的心情是怎样的。如果心情很好,那么我们可以放轻松各种开玩笑。如果女朋友心情不好,那就要谨言慎行,避免女朋友把上班的火撒在你自已身上。四个字来说就是要察言观色。



那么在 Spring 中框架中是如何实现观察这模式的呢?我们来一起看下。在 Spring 中观察者模式主要包含了三部分:Event 事件、Listener 监听者、Publisher 发送者。他们之间的关系可以参考下图来看,Event 事件对应女朋友的心情,Publisher 发送者对应你女朋友,Listener 监听者对应弱小的你。



有了以上对于观察者模式的理解,我们可以看下代码:



在传统的设计模式之中,观察者需要注册到被被观察者当中,这样才可以真正实现状态变化感知。那么在上述 Spring 的观察者模式中,我们好像没有看到,观察者注册到哪里。那么实际上,我们的观察者是注册到了 ApplicationContext 应用上下文中。ApplicationContext 是 Spring 的顶级接口,负责提供应用启动、运行时的上下文信息。AbstractApplicationContext 是其具体的实现,对应的发布事件相关的代码如下所示:


public abstract class AbstractApplicationContext extends DefaultResourceLoader  implements ConfigurableApplicationContext {  ...   @Override public void publishEvent(ApplicationEvent event) {  publishEvent(event, null); }
@Override public void publishEvent(Object event) { publishEvent(event, null); }
protected void publishEvent(Object event, @Nullable ResolvableType eventType) { Assert.notNull(event, "Event must not be null");
// Decorate event as an ApplicationEvent if necessary ApplicationEvent applicationEvent; if (event instanceof ApplicationEvent) { applicationEvent = (ApplicationEvent) event; } else { applicationEvent = new PayloadApplicationEvent<>(this, event); if (eventType == null) { eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType(); } }
// Multicast right now if possible - or lazily once the multicaster is initialized if (this.earlyApplicationEvents != null) { this.earlyApplicationEvents.add(applicationEvent); } else { getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType); }
// Publish event via parent context as well... if (this.parent != null) { if (this.parent instanceof AbstractApplicationContext) { ((AbstractApplicationContext) this.parent).publishEvent(event, eventType); } else { this.parent.publishEvent(event); } } } ...
}
复制代码


适配器模式


所谓适配器模式,按照我的理解其实就是一种转换接口,将两种并不兼容的接口能够实现协调工作。如下图所示,充电插座上面的点并不能直接给手机充电,但是如果我们在手机与充电插座之间通过充电器进行一层转换,那么充电插座的电就可以被转化为为手机充电的电流大小以及电压大小了。



我们再看下Spring框架中是如何使用适配器模式的。我们都知道SpringMVC是用来处理用户请求的,在SpringMVC框架中,有各种各样的Controller,如果没有HandlerAdapter会怎么样。每当有个新的类型的Controller就需要hard code来进行编码添加新的Controller处理方法来应对。但是这样的处理方式不容易维护。因此需要引入适配器模式,对扩展开放,即便有新类型的controller引入也不必要写if else那种不易扩展的代码。


ublic interface HandlerAdapter {    boolean supports(Object var1);
@Nullable ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;
long getLastModified(HttpServletRequest var1, Object var2);}
复制代码


  实现该接口的适配器每一个Controller都有一个适配器与之对应,这样就算有对应新增类型的Controller,我们只要新增对应的adpeter就可以了,大大增强了代码对扩展性。



总结


实际上 Spring 框架中涉及到的设计模式还有很多,本文只是拣出来比较常见的几种设计模式进行阐述。我们在阅读 Spring 框架源码的过程中,一方面需要学习下框架的设计思想,另一方面就需要看看框架中是如何使用各种设计模式来满足对扩展开放、对修改关闭的设计原则的。

发布于: 刚刚阅读数: 3
用户头像

真正的大师永远怀着一颗学徒的心 2018.09.18 加入

InfoQ签约作者、阿里云专家博主,一线大厂高级开发工程师,专注Java后端以及分布式架构,在通往CTO的道路上不断前行。关注公众号:慕枫技术笔记。

评论

发布
暂无评论
向Spring框架学习设计模式_设计模式_慕枫技术笔记_InfoQ写作社区