模板方法在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的,这种实体类,那里面也有一些注意的点,希望你们对于模板方法设计模式呢,能理解透,用好