設計模式(二)之委派模式(Delegate Pattern)深入淺出


學習目標:精簡程序邏輯,提升代碼的可讀性。

內容定位:希望通過對委派模式的學習,讓自己寫出更加優雅的代碼的人群。

委派模式定義:

  • 委派模式(Delegate Pattern)的基本作用是負責任務的調度和分配任務,跟代理模式很像,可以看作是一種特殊情況下的靜態代理的全權代理,但是代理模式注重過程,而委派模式注重結果。
  • 不屬於GOF 23中設計模式之一
  • 屬於行為型模式

 常見應用場景案例:

  • DispatcherServlet
  • 類名以Delegate結尾的
  • 包含Dispatcher的一般都是委派模式
  • Spring框架IOC中的BeanDefinitionParserDelegate:Spring提供多種方式(java、xml、注解)配置bean,該類負責分發處理,注入的bean信息最終會被加載為一個BeanDefition對象(描述對象信息)

 應用場景:解決多任務,又不希望把這些任務或者具體的實現讓用戶知道(不讓用戶直接交互),創建一個中間類,實現全權代理,達到對用戶來說只有一個入口的目的。

生活場景案例

例子:老板需要安排任務給員工,但是又不能直接讓老板去了解每個員工的擅長職能,就可以創建一個中間的經理職位負責了解職員的特長,分發任務。

boss類

/**
 * @ClassName Boss
 * @Author 周聰
 * @Date 2021/1/9 15:48
 * @Version 1.0
 * @Description 老板發布命令
 */
public class Boss {

    /**
     * 發任務
     * @param command
     * @param leader
     */
    public void command(String command,Leader leader){
        leader.doing(command);
    }
}

經理類

/**
 * @ClassName Leader
 * @Author 周聰
 * @Date 2021/1/9 16:04
 * @Version 1.0
 * @Description 項目經理
 */
public class Leader {
//    預先知道每個員工的特長、特征,分發任務
    private Map<String,IEmployee> register = new HashMap<String,IEmployee>();

    public Leader(){
        register.put("加密",new EmployeeA());
        register.put("架構",new EmployeeB());
    }

    public void doing(String command){
//        交給指定的員工去做
        register.get(command).doing(command);
    }
}

員工接口

/**
 * @ClassName IEmployee
 * @Author 周聰
 * @Date 2021/1/9 16:05
 * @Version 1.0
 * @Description 員工接口
 */
public interface IEmployee {

    /**
     * 做事
     * @param command
     */
    void doing(String command);
}

員工A

/**
 * @ClassName EmployeeA
 * @Author 周聰
 * @Date 2021/1/9 16:07
 * @Version 1.0
 * @Description 員工A
 */
public class EmployeeA implements IEmployee {
    @Override
    public void doing(String command) {
        System.out.println("我是員工A,我開始干活了,我擅長加密,執行");
    }
}

員工B

/**
 * @ClassName EmployeeB
 * @Author 周聰
 * @Date 2021/1/9 16:09
 * @Version 1.0
 * @Description 員工B
 */
public class EmployeeB implements IEmployee {
    @Override
    public void doing(String command) {
        System.out.println("我是員工B,我擅長架構,我開始干活了");
    }
}

測試類

/**
 * @ClassName DelegateTest
 * @Author 周聰
 * @Date 2021/1/9 16:18
 * @Version 1.0
 * @Description
 */
public class DelegateTest {

    public static void main(String[] args) {
        new Boss().command("架構",new Leader());
    }
}

業務場景案例(SpringMvc的DispatcherServlet簡單實現)

DispatcherServlet是前端控制器委派模式的實現,提供Spring Web MVC的集中訪問點,負責職責的分派

web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <servlet>
    <servlet-name>delegateServlet</servlet-name>
    <servlet-class>com.zc.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>

<!--  http://localhost:8080/getMemberById.do -->

</web-app>

DispatcherServlet

package com.zc.pattern.delegate.mvc;

import com.zc.pattern.delegate.mvc.controllers.MemberController;
import com.zc.pattern.delegate.mvc.controllers.OrderController;
import com.zc.pattern.delegate.mvc.controllers.SystemController;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @ClassName DispatcherServlet
 * @Author 周聰
 * @Date 2021/1/9 16:31
 * @Version 1.0
 * @Description
 */
public class DispatcherServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        完成調度
        doDispatch(req,resp);
    }

    private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String uri = req.getRequestURI();
        if ("getMemberById".equals(uri)){
            String mid = req.getParameter("mid");
            new MemberController().getMemberById(mid);
        }else if ("getOrderById".equals(uri)){
            String oid = req.getParameter("oid");
            new OrderController().getOrderById(oid);
        }else if ("getSystemById".equals(uri)){
            new SystemController().logout();
        }else {
            resp.getWriter().write("404 not found");
        }
    }
}

MemberController

/**
 * @ClassName MemberController
 * @Author 周聰
 * @Date 2021/1/9 17:09
 * @Version 1.0
 * @Description
 */
public class MemberController {

    public void getMemberById(String mid){
        System.out.println("獲取員工id");
    }
}
OrderController 
/**
 * @ClassName OrderController
 * @Author 周聰
 * @Date 2021/1/9 17:10
 * @Version 1.0
 * @Description
 */
public class OrderController {

    public void getOrderById(String oid){
        System.out.println("獲取訂單id");
    }
}
SystemController 
/**
 * @ClassName SystemController
 * @Author 周聰
 * @Date 2021/1/9 17:11
 * @Version 1.0
 * @Description
 */
public class SystemController {

    public void logout(){
        System.out.println("退出");
    }
}

SpringMvc的DispatcherServlet優化實現

如果Controller過多,要寫很多if...else...,可以利用單例模式策略模式、簡單工廠模式簡化代碼

DispatcherServlet

/**
 * @ClassName DispatcherServlet
 * @Author 周聰
 * @Date 2021/1/9 16:31
 * @Version 1.0
 * @Description DispatcherServlet委派模式案例
 */
public class DispatcherServlet extends HttpServlet {
    /**
     * 容器保存映射關系,單例模式體現,每一個Controller自始至終都使用同一個實例
     */
    private List<Handler> handlerMapping = new ArrayList<Handler>();

    /**
     * 重寫init方法,建立好映射關系
     */
    @Override
    public void init() throws ServletException {
        Class<?> memberControllerClass = MemberController.class;
        Class<?> orderControllerClass = OrderController.class;
        Class<?> systemControllerClass = SystemController.class;
        try {
//      簡單工廠模式體現 handlerMapping.add(
new Handler().setController(memberControllerClass.newInstance()) .setMethod(memberControllerClass.getMethod("getMemberById", String.class)) .setUrl("/web/getMemberById.json")); handlerMapping.add(new Handler().setController(orderControllerClass.newInstance()) .setMethod(orderControllerClass.getMethod("getOrderById", String.class)) .setUrl("/web/getOrderById.json")); handlerMapping.add(new Handler().setController(systemControllerClass.newInstance()) .setMethod(systemControllerClass.getMethod("logout")) .setUrl("/web/logout.json")); } catch (Exception e) { e.printStackTrace(); } } @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 完成調度 doDispatch(req,resp); } private void doDispatch(HttpServletRequest req, HttpServletResponse resp) { String uri = req.getRequestURI(); Handler handler = null; // 策略模式的體現,避免了重復的if...else...代碼 for (Handler h : handlerMapping) { if (h.getUrl().equals(uri)){ handler = h; break; } } if (handler != null){ try { // 委派模式體現 Object obj = handler.getMethod().invoke(handler.getController(), req.getParameter("mid")); resp.getWriter().write(obj.toString()); } catch (Exception e) { e.printStackTrace(); } } } class Handler{ private Object controller; private Method method; private String url; /** * 修改set方法返回對象,方便鏈式調用 */ 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; } } }

設計模式從來都是多個整合使用的

 

以上對委派模式的介紹到此結束,歡迎批評指正。 附:源碼地址


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM