委派模式
在設(shè)計模式中虫腋,似乎沒有委派模式這一模式,就想魯迅說的稀余,世界上本么沒有路悦冀,走的人多了便成了路。正是因為這種邏輯被多次用到睛琳,便被前人總結(jié)為委派設(shè)計模式盒蟆。
委派模式(Delegate Pattern)的作用就是負(fù)責(zé)任務(wù)的調(diào)度和分配任務(wù),跟代理模式很像师骗,可以看做是一種特殊情況下的靜態(tài)代理的全權(quán)代理历等,但是代理注重過程,而委派模式注重結(jié)果辟癌。
委派模式跟我們程序員的生態(tài)圈非常像寒屯,需求來了,項目經(jīng)理根據(jù)程序員的能力來進行分配愿待,這個的過程就是委派浩螺,對于提出需求的人來說,我們程序員是不可見的仍侥。
舉一個簡單的例子
1、創(chuàng)建程序員接口和程序員
public interface Employee {
void doing(String command);
}
public class ProgramerA implements Employee{
@Override
public void doing(String command){
System.out.println("我擅長加密:我正在做:"+command);
}
}
public class ProgramerB implements Employee{
@Override
public void doing(String command){
System.out.println("我擅長架構(gòu):我正在做:"+command);
}
}
2鸳君、創(chuàng)建項目經(jīng)理
public class Leader {
// 預(yù)先知道每個員工的特長农渊、特征、分發(fā)任務(wù)
Map<String,Employee> register = new HashMap<>();
public Leader(){
register.put("加密",new ProgramerA());
register.put("架構(gòu)",new ProgramerB());
}
public void doing(String command){
register.get(command).doing(command);
}
}
3或颊、創(chuàng)建甲方用戶,用戶只與leader聯(lián)系
public class Customer {
public void command(String command, Leader leader){
leader.doing(command);
}
}
4砸紊、測試
用戶有一個加密任務(wù)交給項目經(jīng)理,項目經(jīng)理進行委派
public class AppTest {
public static void main(String[] args) {
new Customer().command("加密",new Leader());
}
}
我擅長加密:我正在做:加密
類圖
從類圖中可以看出Leader是作為中間人協(xié)調(diào)用戶的任務(wù)和程序員的工作的囱挑。而且類圖中也提現(xiàn)了與靜態(tài)代理的區(qū)別醉顽,Leader只是依賴接口,并不繼承接口平挑。一般地游添,帶有delegate或者dispatcher都可以先聯(lián)想委派模式。
比如我們熟悉的DispatherServlet通熄,SpringMVC中負(fù)責(zé)請求分發(fā)處理的唆涝,我們只需關(guān)注它的dispatch方法
doDispatch() 方法進行請求分發(fā)處理,doDispatch() 方法的主要過程是通過 HandlerMapping 獲取 Handler唇辨,再找到用于執(zhí)行它的 HandlerAdapter廊酣,執(zhí)行 Handler 后得到 ModelAndView ,ModelAndView 是連接“業(yè)務(wù)邏輯層”與“視圖展示層”的橋梁赏枚,接下來就要通過 ModelAndView 獲得 View亡驰,再通過它的 Model 對 View 進行渲染晓猛。想深入研究DispatcherServlet可以去看這篇文章,寫的很好DispatcherServlet詳解
這里可以關(guān)注第21行凡辱,這里就是委派模式的體現(xiàn)
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
// 獲取當(dāng)前請求的WebAsyncManager戒职,如果沒找到則創(chuàng)建并與請求關(guān)聯(lián)
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 檢查是否有 Multipart,有則將請求轉(zhuǎn)換為 Multipart 請求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 遍歷所有的 HandlerMapping 找到與請求對應(yīng)的 Handler煞茫,并將其與一堆攔截器封裝到 HandlerExecution 對象中帕涌。
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// 遍歷所有的 HandlerAdapter,找到可以處理該 Handler 的 HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 處理 last-modified 請求頭
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 遍歷攔截器续徽,執(zhí)行它們的 preHandle() 方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
try {
// 執(zhí)行實際的處理程序
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
applyDefaultViewName(request, mv);
// 遍歷攔截器王浴,執(zhí)行它們的 postHandle() 方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception ex) {
dispatchException = ex;
}
// 處理執(zhí)行結(jié)果蹲嚣,是一個 ModelAndView 或 Exception,然后進行渲染
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
} catch (Exception ex) {
} catch (Error err) {
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// 遍歷攔截器,執(zhí)行它們的 afterCompletion() 方法
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
return;
}
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}