【从优秀源码中学习设计模式】---模板模式

前言

本文以Java语言为主,分析包括JDK、Spring、MyBatis、Guava、org.apache.xxx中,等一些优秀的开源代码、项目,在这些开源代码、项目中都包含了大量的设计模式,通过对它们进行分析,能够快速帮助我们学会设计模式的使用方式,由理论过渡到实践中,进而真正了解设计模式的思想,由于内容较多,所以每个设计模式单独写一篇文章,需要了解其他模式请点击对应链接跳转。

建造者模式
装饰器模式
适配器模式
策略模式

模板模式

模板模式是一种非常广泛、实用的设计模式。

Spring

Spring中最熟悉应该就是AbstractApplicationContext类的中refresh方法了,其中定义了十几个方法,有些方法并没有具体的实现,而是让其子类去实现。

@Override
public void refresh() throws BeansException, IllegalStateException {
    
    
	synchronized (this.startupShutdownMonitor) {
    
    
		// Prepare this context for refreshing.
		prepareRefresh();
		// Tell the subclass to refresh the internal bean factory.
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
		// Prepare the bean factory for use in this context.
		prepareBeanFactory(beanFactory);
		try {
    
    
			// Allows post-processing of the bean factory in context subclasses.
			postProcessBeanFactory(beanFactory);
			// Invoke factory processors registered as beans in the context.
			invokeBeanFactoryPostProcessors(beanFactory);
			// Register bean processors that intercept bean creation.
			registerBeanPostProcessors(beanFactory);
			// Initialize message source for this context.
			initMessageSource();
			// Initialize event multicaster for this context.
			initApplicationEventMulticaster();
			// Initialize other special beans in specific context subclasses.
			onRefresh();
			// Check for listener beans and register them.
			registerListeners();
			// Instantiate all remaining (non-lazy-init) singletons.
			finishBeanFactoryInitialization(beanFactory);
			// Last step: publish corresponding event.
			finishRefresh();
		}
		catch (BeansException ex) {
    
    
			if (logger.isWarnEnabled()) {
    
    
				logger.warn("Exception encountered during context initialization - " +
						"cancelling refresh attempt: " + ex);
			}
			// Destroy already created singletons to avoid dangling resources.
			destroyBeans();
			// Reset 'active' flag.
			cancelRefresh(ex);
			// Propagate exception to caller.
			throw ex;
		}
		finally {
    
    
			// Reset common introspection caches in Spring's core, since we
			// might not ever need metadata for singleton beans anymore...
			resetCommonCaches();
		}
	}
}

prepareRefresh()方法,不同的实现类,都有各自对应的处理方法
在这里插入图片描述

onRefresh()方法,则是专门留给子类去实现的

/**
 * Template method which can be overridden to add context-specific refresh work.
 * Called on initialization of special beans, before instantiation of singletons.
 * <p>This implementation is empty.
 * @throws BeansException in case of errors
 * @see #refresh()
 */
protected void onRefresh() throws BeansException {
    
    
	// For subclasses: do nothing by default.
}

MyBatis

BaseExecutor抽象类中定义了一些抽象方法,让其子类实现

public abstract class BaseExecutor implements Executor {
    
    
...
}

在这里插入图片描述
我们随便选一个doQuery()方法,入口在BaseExecutor提供的queryFromDatabase方法中

在这里插入图片描述
选择其中一个子类BatchExceutor点进去

public class BatchExecutor extends BaseExecutor {
    
    
...
}

在这里插入图片描述
其中flushStatements()、getConnection(ms.getStatementLog())、closeStatement(stmt)调用的又都是BaseExecutor中定义的方法。

JDK

JDK中也有非常经典的应用场景,以前我们刚开始学习Servlet时,一定写过doGet、doPost这两个方法,这实际上也是模板模式。

我们自己写一个Servlet时只需要继承HttpServlet类,重写下面两个方法即可,其中的流程全部交由Servlet处理

protected void doPost(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
{
    
    
    String protocol = req.getProtocol();
    String msg = lStrings.getString("http.method_post_not_supported");
    if (protocol.endsWith("1.1")) {
    
    
        resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
    } else {
    
    
        resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
    }
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
{
    
    
    String protocol = req.getProtocol();
    String msg = lStrings.getString("http.method_get_not_supported");
    if (protocol.endsWith("1.1")) {
    
    
        resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
    } else {
    
    
        resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
    }
}

おすすめ

転載: blog.csdn.net/CSDN_WYL2016/article/details/121235087