Template Method parse the source code (jdk + servlet + mybatis)

模板方法在JDK中的一些应用,AbstractList这么一个抽象类,

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E>

我们看一下他的实现,就知道这个类是做什么的,可以看到在很多开源包中,都实现了这个类,那他肯定是为了扩展,

自己List这个数据结构的,然后JDK中ArrayList,你们应该都很熟悉,那在这个类里边,有一个addAll方法,包括其他方法

也是类似的,

/**
 * {@inheritDoc}
 *
 * <p>This implementation gets an iterator over the specified collection
 * and iterates over it, inserting the elements obtained from the
 * iterator into this list at the appropriate position, one at a time,
 * using {@code add(int, E)}.
 * Many implementations will override this method for efficiency.
 *
 * <p>Note that this implementation throws an
 * {@code UnsupportedOperationException} unless
 * {@link #add(int, Object) add(int, E)} is overridden.
 *
 * @throws UnsupportedOperationException {@inheritDoc}
 * @throws ClassCastException            {@inheritDoc}
 * @throws NullPointerException          {@inheritDoc}
 * @throws IllegalArgumentException      {@inheritDoc}
 * @throws IndexOutOfBoundsException     {@inheritDoc}
 */
public boolean addAll(int index, Collection<? extends E> c) {
	rangeCheckForAdd(index);
	boolean modified = false;
	for (E e : c) {
		add(index++, e);
		modified = true;
	}
	return modified;
}

我们先选择一个来看,例如说addAll,这里就可以理解成他呢是对外开放的一个方法,这里面的具体实现呢,就可以理解

成addAll这个算法里面的具体顺序,以及步骤,那对于很多List的实现呢,他们get获取具体元素的实现呢,是不一样的,

那我们看一下get这个方法

/**
 * {@inheritDoc}
 *
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
abstract public E get(int index);

可以看到他是abstract方法,是一个抽象的方法,完全交由子类来实现,我们来看一下ArrayList里面的get

/**
 * Returns the element at the specified position in this list.
 *
 * @param  index index of the element to return
 * @return the element at the specified position in this list
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public E get(int index) {
	rangeCheck(index);

	return elementData(index);
}

这里面实现了他的父类AbstractList里面的get方法,里面有两个步骤,首先进行范围的一个check,然后通过这个索引,返回

具体的elementData,其他也是同理,那对于这个抽象List,当然会有抽象Set,

public abstract class AbstractSet<E> extends AbstractCollection<E> implements Set<E>

那既然有抽象Set,那就会有抽象Map

public abstract class AbstractMap<K,V> implements Map<K,V>

他们三个都是同理,里面定义一套算法模板,该开放的开放,该自己实现的自己来实现,然后我们再看一下模板方法在servlet里面的

实现,这个类相信你们都非常的熟悉,HttpServlet,他在这个类里面有几个非常重要的方法,比如我们经常使用的doGet,

public abstract class HttpServlet extends GenericServlet

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);
	}
}

还有doPost,

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这么一个权限的方法

    protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {

        String method = req.getMethod();

        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                // servlet doesn't support if-modified-since, no reason
                // to go through further expensive logic
                doGet(req, resp);
            } else {
                long ifModifiedSince;
                try {
                    ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                } catch (IllegalArgumentException iae) {
                    // Invalid date header - proceed as if none was set
                    ifModifiedSince = -1;
                }
                if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                    // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);

        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);

        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);

        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);

        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);

        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);

        } else {
            //
            // Note that this means NO servlet supports whatever
            // method was requested, anywhere on this server.
            //

            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);

            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }
	
这个类就定义了一个处理模板,我们平时使用的时候,只要继承这个Servlet,并且实现doGet,doPost,这两个方法就可以了,

当然还有do其他类型的,那在SpringMVC数据绑定中,你们可以学习一下,那些也是有讲的,在RestFul这个章节,也就是这个类定义了

一套模板,子类可以来重写doGet,或者doPost,或者doXxx这么一个方法,按这个也是模板设计模式在servlet中的一些应用,那在Mybatis

当中,当然也有对应的应用,看一下BaseExecutor这么一个类

public abstract class BaseExecutor implements Executor

回到最上边我们看一下,首先这个类是抽象类,翻译过来就是一个基础的执行人,实现了执行人接口,我们看一下这里面的方法,这里面的

方法有很多,他实现了大部分的SQL执行逻辑,然后把几个方法交给子类来定制化执行,我们看一下doUpdate这个方法

protected abstract int doUpdate(MappedStatement ms, Object parameter)
  throws SQLException;

还有doFlush,doQuery,doQueryCursor

protected abstract List<BatchResult> doFlushStatements(boolean isRollback)
  throws SQLException;

protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
  throws SQLException;

protected abstract <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql)
  throws SQLException;

这四个方法完全是抽象方法,交由子类来实现,那么这个类都有哪些子类呢,我们来看一下,一共有这四个子类,简单的,

close的,Batch,reuse

我们随便看一个,比如doUpdate,这四个子类中都有具体的实现,比如Simple里面的

@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
  Configuration configuration = ms.getConfiguration();
  StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
  stmt = prepareStatement(handler, ms.getStatementLog());
  return handler.update(stmt);
} finally {
  closeStatement(stmt);
}
}

Executor这个类有四个实现类,分别对应不同的业务场景,比如刚刚说的Batch,这个是对应批量Update来使用的

public class BatchExecutor extends BaseExecutor

从名字就能看出来,而Reuse就是重用的

public class ReuseExecutor extends BaseExecutor

Simple就是简单的

/**
 * @author Clinton Begin
 */
public class SimpleExecutor extends BaseExecutor 

那我们看一下简单的doUpdate是怎么实现的呢,只所以定义为SimpleExecutor呢,是因为这里的实现足够简单,例如每执行一次

Update的时候,这里就new了一个newStatementHandler,

@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
  Configuration configuration = ms.getConfiguration();
  StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
  stmt = prepareStatement(handler, ms.getStatementLog());
  return handler.update(stmt);
} finally {
  closeStatement(stmt);
}
}

后面是具体的各种参数,每执行一次就new一个newStatementHandler,然后通过handler来生成一个statement,然后执行update,

执行完成之后,在finally里面进行关闭,而BatchExecutor里边呢

/**
 * @author Jeff Butler 
 */
public class BatchExecutor extends BaseExecutor 

考虑的批量执行update语句,有兴趣的可以仔细来阅读以下

  @Override
  public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
    final Configuration configuration = ms.getConfiguration();
    final StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, null, null);
    final BoundSql boundSql = handler.getBoundSql();
    final String sql = boundSql.getSql();
    final Statement stmt;
    if (sql.equals(currentSql) && ms.equals(currentStatement)) {
      int last = statementList.size() - 1;
      stmt = statementList.get(last);
      applyTransactionTimeout(stmt);
     handler.parameterize(stmt);//fix Issues 322
      BatchResult batchResult = batchResultList.get(last);
      batchResult.addParameterObject(parameterObject);
    } else {
      Connection connection = getConnection(ms.getStatementLog());
      stmt = handler.prepare(connection, transaction.getTimeout());
      handler.parameterize(stmt);    //fix Issues 322
      currentSql = sql;
      currentStatement = ms;
      statementList.add(stmt);
      batchResultList.add(new BatchResult(ms, sql, parameterObject));
    }
  // handler.parameterize(stmt);
    handler.batch(stmt);
    return BATCH_UPDATE_RETURN_VALUE;
  }

那这些都是模板方法设计模式在JDK,Servlet,以及Mybatis中的一些应用,模板方法这个设计模式,比较简单,相信通过这里的学习,

是非常容易理解,模板方法设计模式的,同时我们在定制的时候,也注意一下,特意设置的设计模式课程,和前端课程,这两个不是

一个level的,这种实体类,那里面也有一些注意的点,希望你们对于模板方法设计模式呢,能理解透,用好

 

Guess you like

Origin blog.csdn.net/Leon_Jinhai_Sun/article/details/91416378