向Spring框架学习设计模式

Java
310
0
0
2023-05-04

引言

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

...
}

观察者模式

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

img

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

img

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

// Event事件
public class GFMoodEvent extends ApplicationEvent 
{ 
 private String message; 
 public GFMoodEvent(Object source, String message) 
 { 
  super(source); 
 }
  public String getMessage() { 
   return this.message; 
  }
 }
 // Listener监听者
 @Component
 public class GFMoodListener implements ApplicationListener 
 { 
  @Override 
  public void onApplicationEvent(GFMoodEvent gFMoodEvent) 
  { 
   String message = gFMoodEvent.getMessage();  
   System.out.println(message); 
   }}
   
 // Publisher发送者
 @Component
 public class GFMoodPublisher { 
  @Autowired 
  private ApplicationContext applicationContext; 
   
  public void publishEvent(GFMoodEvent gFMoodEvent) { 
   this.applicationContext.publishEvent(gFMoodEvent); 
   }
  }


在传统的设计模式之中,观察者需要注册到被被观察者当中,这样才可以真正实现状态变化感知。那么在上述Spring的观察者模式中,我们好像没有看到,观察者注册到哪里。那么实际上,我们的观察者是注册到了ApplicationContext应用上下文中。ApplicationContextSpring的顶级接口,负责提供应用启动、运行时的上下文信息。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);
   }
  }
 }
  ...

}

适配器模式

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

img

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

public 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就可以了,大大增强了代码对扩展性。

img

总结

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