设计模式-问题-委派模式+模板模式+策略模式+责任链模式
委派模式
委派主要解决什么问题,什么情况下要委派。
主要是负责任务的调度和处理,我们有一个管理者,和一些执行者,管理者把任务分配给执行者的情况下需要委派。
也可以说是一个大任务需要拆分成多个子任务,但是别人只需要我们把任务执行完,这时候就可以采用委派模式。
模板模式
模板方法本质解决了一个什么问题,回忆一下spring/mybatis怎么用模板模式的?你在工作中会用了嘛?
解决问题
子类有共同的方法
通过父类来拼接模板
封装不变的部分,扩展可变的部分
行为由父类控制,子类负责实现
Spring模板方法
JDBCTemplate
FrameworkServlet
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { long startTime = System.currentTimeMillis(); Throwable failureCause = null; LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); LocaleContext localeContext = buildLocaleContext(request); RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor()); initContextHolders(request, localeContext, requestAttributes); try { doService(request, response); } catch (ServletException ex) { failureCause = ex; throw ex; } protected abstract void doService(HttpServletRequest request, HttpServletResponse response) throws Exception;
AbstractBeanFactory
AbstractRoutingDataSource
org.springframework.web.servlet.view.AbstractTemplateView
Mybatis模板方法
Mybatis BaseExecute

Executor是一个基础的SQL执行类,他实现了大部分的SQL执行逻辑,然后把几个方法交给子类定制化来完成。
例如
doUpdate
doFlushStatement
doQuery
doQueryCursor
查询方法
看到org.apache.ibatis.executor.BaseExecutor#commit
他的提交方法会调用刷新也就是提交到数据库去,但是具体的实现可能提交的时机是不一样的,例如SimpleExecutor是立即提交,但是BatchExecutor是存一堆然后一起提交。
public void commit(boolean required) throws SQLException {
if (closed) {
throw new ExecutorException("Cannot commit, transaction is already closed");
}
clearLocalCache();
flushStatements();
if (required) {
transaction.commit();
}
}
public List<BatchResult> flushStatements(boolean isRollBack) throws SQLException {
if (closed) {
throw new ExecutorException("Executor was closed.");
}
return doFlushStatements(isRollBack);
}
protected abstract List<BatchResult> doFlushStatements(boolean isRollback)
throws SQLException;
此时查看具体的类的doFlushStatements
ReuseExecutor
org.apache.ibatis.executor.ReuseExecutor#doFlushStatements
private final Map<String, Statement> statementMap = new HashMap<>();
public List<BatchResult> doFlushStatements(boolean isRollback) {
for (Statement stmt : statementMap.values()) {
closeStatement(stmt);
}
statementMap.clear();
return Collections.emptyList();
}
ReuseExecutor因为需要重用相同语句的Statement所以在提交的时候需要把那些都清空
SimpleExecutor
org.apache.ibatis.executor.SimpleExecutor#doQuery
@Override
public List<BatchResult> doFlushStatements(boolean isRollback) {
return Collections.emptyList();
}
SimpleExecutor则不需要做任何操作
BatchExecutor
org.apache.ibatis.executor.BatchExecutor#doQuery
public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
try {
List<BatchResult> results = new ArrayList<>();
if (isRollback) {
return Collections.emptyList();
}
for (int i = 0, n = statementList.size(); i < n; i++) {
Statement stmt = statementList.get(i);
applyTransactionTimeout(stmt);
BatchResult batchResult = batchResultList.get(i);
try {
batchResult.setUpdateCounts(stmt.executeBatch());
MappedStatement ms = batchResult.getMappedStatement();
List<Object> parameterObjects = batchResult.getParameterObjects();
KeyGenerator keyGenerator = ms.getKeyGenerator();
if (Jdbc3KeyGenerator.class.equals(keyGenerator.getClass())) {
Jdbc3KeyGenerator jdbc3KeyGenerator = (Jdbc3KeyGenerator) keyGenerator;
jdbc3KeyGenerator.processBatch(ms, stmt, parameterObjects);
} else if (!NoKeyGenerator.class.equals(keyGenerator.getClass())) { //issue #141
for (Object parameter : parameterObjects) {
keyGenerator.processAfter(this, ms, stmt, parameter);
}
}
// Close statement to close cursor #1109
closeStatement(stmt);
} catch (BatchUpdateException e) {
StringBuilder message = new StringBuilder();
message.append(batchResult.getMappedStatement().getId())
.append(" (batch index #")
.append(i + 1)
.append(")")
.append(" failed.");
if (i > 0) {
message.append(" ")
.append(i)
.append(" prior sub executor(s) completed successfully, but will be rolled back.");
}
throw new BatchExecutorException(message.toString(), e, results, batchResult);
}
results.add(batchResult);
}
return results;
} finally {
for (Statement stmt : statementList) {
closeStatement(stmt);
}
currentSql = null;
statementList.clear();
batchResultList.clear();
}
}
BatchExecutor则需要一批一批的来提交
所以可以看到公共的方法在父类中实现了,具体的差异性的内容都交给子类来实现钩子方法了
策略模式
为什么还需要封装一个工厂来使用策略模式
通过工厂来获取具体的策略这样我们就能够多次去选择和使用策略
我们通过工厂来记录当前有哪一些策略模式
通过工厂我们每次创建新的策略不需要来改动过多的代码,并且能够让我们对扩展开发对修改关闭
策略模式有弊端,客户端必须知道所有策略,并且需要自己来决定使用哪一个策略
策略模式使用前提是什么?即满足什么条件你才能去选策略?真正用的时候需要告诉客户端什么
使用前提
不同的类行为是不一样的
客户端使用只会使用到其中一种策略
需要屏蔽不同算法和算法之间的关系
客户端需要知道
需要知道所有策略,并且需要自行选择其中一个
责任链模式
想一想责任链模式的使用场景请具体举出来,请认真体会一下责任链模式的优点
能够帮我们把请求和处理分开,使用者不需要知道是谁处理的
需要注意链路过长的问题,一般通过增加链路的时候判断最大长度来避免无意识破坏系统性鞥
常用场景
例如公司里面发起审批流程
需要先部门经理审核然后是技术总监审核最后是老板
例如我们对请求的拦截过滤FilterChain也是一层一层处理的
比如说Netty中的pipeline
只要是处理着不需要知道请求的全貌,服务端可以把处理逻辑构建成一条链路的都能够使用责任链来使用
Last updated