设计模式之委派模式

委派模式,大名鼎鼎的Spring都在使用。读懂Spring源码必备的设计模式之一

1、What is the delegate pattern?

​ 委派模式不是Gof23中的设计模式,但是它能精简程序的逻辑,提高代码的可读性,消除大量的if/esle或switch语句。委派模式就是负责任务的调度和分配。大名鼎鼎的SpringMVC中的DispatcherServlet就是使用到了委派模式。从下图可以看得出来,DispatchServlert把查找Handler、执行Handler、解析视图等工作分配给其他组件去做。在Spring中由Delegate字眼的类都是使用了委派模式,顾名思义嘛~

springmvc-delegate

2、代码实现委派模式

下面使用委派模式:通过Leader分配任务给其他人。新建业务接口IExecutor

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package com.msr.study.patterns.behavioral.delegate;

public interface IExecutor {

    /**
     * 开始工作
     *
     * @param command
     */
    void doJob(String command);
}

业务接口IExecutor的实现类JavaEngineerFrontendEngineerOpsEngineer

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.msr.study.patterns.behavioral.delegate;
public class JavaEngineer implements IExecutor {
    @Override
    public void doJob(String command) {
        System.out.println("Java工程师开始工作: " + command);
    }
}


package com.msr.study.patterns.behavioral.delegate;
public class FrontendEngineer implements IExecutor {
    @Override
    public void doJob(String command) {
        System.out.println("前端工程师开始工作:"+command);
    }
}


package com.msr.study.patterns.behavioral.delegate;
public class OpsEngineer implements IExecutor {
    @Override
    public void doJob(String command) {
        System.out.println("运维工程师开始工作:" + command);
    }
}

新建个枚举类,标识不同的业务类型

1
2
3
4
package com.msr.study.patterns.behavioral.delegate;
public enum CommandEnum {
    JAVA,FRONTEND,OPS;
}

Leader类负责分派任务

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.msr.study.patterns.behavioral.delegate;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class Leader implements IExecutor {
    private Map<String, IExecutor> map = new ConcurrentHashMap<>();
    public Leader() {
        map.put(CommandEnum.JAVA.name(),new JavaEngineer());
        map.put(CommandEnum.FRONTEND.name(),new FrontendEngineer());
        map.put(CommandEnum.OPS.name(),new OpsEngineer());
    }
    @Override
    public void doJob(String command) {
        map.get(command).doJob(command);
    }
}


//测试
package com.msr.study.patterns.behavioral.delegate;
public class DelegateTest {
    public static void main(String[] args) {
        //看上去好像都是leader在工作,其实是leader委派给了其他人去工作
        Leader leader = new Leader();
        leader.doJob(CommandEnum.JAVA.name());
        leader.doJob(CommandEnum.OPS.name());
    }
}

运行结果:

1
2
Java工程师开始工作: JAVA
运维工程师开始工作:OPS

3、Spring中委派模式的使用

​ 前面说到过Spring中委派模式使用的类是以Delegate结尾的,在开发工具中搜索一下Delegate。虽然DispatcherServlet不是delegate结尾,不过还是由应用委派模式。DispatcherServlert中的doService()方法中是调用了doDispatch()方法去查找Handler,执行handle()方法处理用户请求。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ...
        try {
            try {
                ModelAndView mv = null;
                Exception dispatchException = null;
                try {
                    processedRequest = this.checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
                    mappedHandler = this.getHandler(processedRequest);
                    if (mappedHandler == null || mappedHandler.getHandler() == null) {
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }
					//找到HandlerAdapter
                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                    String method = request.getMethod();
                    boolean isGet = "GET".equals(method);
                    if (isGet || "HEAD".equals(method)) {
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        if (this.logger.isDebugEnabled()) {
                            this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                        }

                        if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }

                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }

                    try {
                        //委派url对应Handler去处理请求
                        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    } finally {
                        if (asyncManager.isConcurrentHandlingStarted()) {
                            return;
                        }

                    }

                    this.applyDefaultViewName(request, mv);
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var27) {
                    dispatchException = var27;
                }

                this.processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
            } catch (Exception var28) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, var28);
            } catch (Error var29) {
                this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, var29);
            }

        } finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                return;
            } else {
                if (multipartRequestParsed) {
                    this.cleanupMultipart(processedRequest);
                }

            }
        }
    }