委派模式的定義及應(yīng)用場(chǎng)景
委派模式不屬于 GOF23 種設(shè)計(jì)模式中。委派模式(Delegate Pattern)的基本作用就是 負(fù)責(zé)任務(wù)的調(diào)用和分配任務(wù)班挖,跟代理模式很像,可以看做是一種特殊情況下的靜態(tài)代理 的全權(quán)代理芯砸,但是代理模式注重過(guò)程萧芙,而委派模式注重結(jié)果。委派模式在 Spring 中應(yīng)用 非常多假丧,大家常用的 DispatcherServlet 其實(shí)就是用到了委派模式∷荆現(xiàn)實(shí)生活中也常有委 派的場(chǎng)景發(fā)生,例如:老板(Boss)給項(xiàng)目經(jīng)理(Leader)下達(dá)任務(wù)包帚,項(xiàng)目經(jīng)理會(huì)根據(jù) 實(shí)際情況給每個(gè)員工派發(fā)工作任務(wù)渔期,待員工把工作任務(wù)完成之后,再由項(xiàng)目經(jīng)理匯報(bào)工 作進(jìn)度和結(jié)果給老板渴邦。我們用代碼來(lái)模擬下這個(gè)業(yè)務(wù)場(chǎng)景擎场,先來(lái)看一下類圖:
創(chuàng)建 IEmployee 員工接口:
public interface IEmployee {
public void doing(String command);
}
創(chuàng)建員工 EmployeeA 類:
public class EmployeeA implements IEmployee {
@Override
public void doing(String command) {
System.out.println("我是員工A羽德,我現(xiàn)在開(kāi)始干" + command + "工作");
}
}
創(chuàng)建員工 EmployeeB 類:
public class EmployeeB implements IEmployee {
@Override
public void doing(String command) {
System.out.println("我是員工B,我現(xiàn)在開(kāi)始干" + command + "工作");
}
}
創(chuàng)建項(xiàng)目經(jīng)理 Leader 類:
public class Leader implements IEmployee {
private Map<String,IEmployee> targets = new HashMap<String,IEmployee>();
public Leader() {
targets.put("加密",new EmployeeA());
targets.put("登錄",new EmployeeB());
}
//項(xiàng)目經(jīng)理自己不干活
public void doing(String command){
targets.get(command).doing(command);
}
}
創(chuàng)建 Boss 類下達(dá)命令:
public class Boss {
public void command(String command,Leader leader){
leader.doing(command);
}
}
測(cè)試代碼:
public class DelegateTest {
public static void main(String[] args) {
//客戶請(qǐng)求(Boss)迅办、委派者(Leader)宅静、被被委派者(Target)
//委派者要持有被委派者的引用
//代理模式注重的是過(guò)程, 委派模式注重的是結(jié)果
//策略模式注重是可擴(kuò)展(外部擴(kuò)展)站欺,委派模式注重內(nèi)部的靈活和復(fù)用
//委派的核心:就是分發(fā)姨夹、調(diào)度、派遣
//委派模式:就是靜態(tài)代理和策略模式一種特殊的組合
new Boss().command("登錄",new Leader());
}
}
通過(guò)上面的代碼矾策,生動(dòng)地還原了項(xiàng)目經(jīng)理分配工作的業(yè)務(wù)場(chǎng)景磷账,也是委派模式的生動(dòng)體現(xiàn)。
委派模式在源碼中的體現(xiàn)
下面我們?cè)賮?lái)還原一下 SpringMVC 的 DispatcherServlet 是如何實(shí)現(xiàn)委派模式的贾虽。創(chuàng)建 業(yè)務(wù)類 MemberController:
public class MemberController {
public void getMemberById(String mid){
}
}
OrderController 類:
public class OrderController {
public void getOrderById(String mid){
}
}
SystemController 類:
public class SystemController {
public void logout(){
}
}
創(chuàng)建 DispatcherServlet 類:
/**
* 相當(dāng)于是項(xiàng)目經(jīng)理的角色
* Created by Tom.
*/
public class DispatcherServlet extends HttpServlet{
private List<Handler> handlerMapping = new ArrayList<Handler>();
public void init() throws ServletException {
try {
Class<?> memberControllerClass = MemberController.class;
handlerMapping.add(new Handler()
.setController(memberControllerClass.newInstance())
.setMethod(memberControllerClass.getMethod("getMemberById", new Class[]{String.class}))
.setUrl("/web/getMemberById.json"));
}catch(Exception e){
}
}
// private void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception{
//
// String uri = request.getRequestURI();
//
// String mid = request.getParameter("mid");
//
// if("getMemberById".equals(uri)){
// new MemberController().getMemberById(mid);
// }else if("getOrderById".equals(uri)){
// new OrderController().getOrderById(mid);
// }else if("logout".equals(uri)){
// new SystemController().logout();
// }else {
// response.getWriter().write("404 Not Found!!");
// }
//
// }
private void doDispatch(HttpServletRequest request, HttpServletResponse response){
//1逃糟、獲取用戶請(qǐng)求的url
// 如果按照J(rèn)2EE的標(biāo)準(zhǔn)、每個(gè)url對(duì)對(duì)應(yīng)一個(gè)Serlvet蓬豁,url由瀏覽器輸入
String uri = request.getRequestURI();
//2绰咽、Servlet拿到url以后,要做權(quán)衡(要做判斷地粪,要做選擇)
// 根據(jù)用戶請(qǐng)求的URL取募,去找到這個(gè)url對(duì)應(yīng)的某一個(gè)java類的方法
//3、通過(guò)拿到的URL去handlerMapping(我們把它認(rèn)為是策略常量)
Handler handle = null;
for (Handler h: handlerMapping) {
if(uri.equals(h.getUrl())){
handle = h;
break;
}
}
//4蟆技、將具體的任務(wù)分發(fā)給Method(通過(guò)反射去調(diào)用其對(duì)應(yīng)的方法)
Object object = null;
try {
object = handle.getMethod().invoke(handle.getController(),request.getParameter("mid"));
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//5玩敏、獲取到Method執(zhí)行的結(jié)果,通過(guò)Response返回出去
// response.getWriter().write();
}
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
doDispatch(req,resp);
} catch (Exception e) {
e.printStackTrace();
}
}
class Handler{
private Object controller;
private Method method;
private String url;
public Object getController() {
return controller;
}
public Handler setController(Object controller) {
this.controller = controller;
return this;
}
public Method getMethod() {
return method;
}
public Handler setMethod(Method method) {
this.method = method;
return this;
}
public String getUrl() {
return url;
}
public Handler setUrl(String url) {
this.url = url;
return this;
}
}
}
配置 web.xml 文件:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<display-name>Gupao Web Application</display-name>
<servlet>
<servlet-name>delegateServlet</servlet-name>
<servlet-class>com.gupaoedu.vip.pattern.delegate.mvc.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>delegateServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
一個(gè)完整的委派模式就實(shí)現(xiàn)出來(lái)了质礼。當(dāng)然旺聚,在 Spring 中運(yùn)用到委派模式不僅于此,還有 很多眶蕉。小伙伴們可以通過(guò)命名就可以識(shí)別翻屈。在 Spring 源碼中妻坝,只要以 Delegate 結(jié)尾的 都是實(shí)現(xiàn)了委派模式伸眶。例如:BeanDefinitionParserDelegate 根據(jù)不同類型委派不同的 邏輯解析 BeanDefinition。