zoukankan      html  css  js  c++  java
  • 设计模式(二)之委派模式(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; } } }

    设计模式从来都是多个整合使用的

    以上对委派模式的介绍到此结束,欢迎批评指正。 附:源码地址

  • 相关阅读:
    ConcurrentHashMap的size方法是线程安全的吗?
    redis cluster介绍与gossip协议
    leetcode刷题篇 21题合并两个排序的链表 java C++版本
    MySQL索引凭什么能让查询效率提高这么多?
    从零开始学习html(十五)css样式设置小技巧——下
    从零开始学习html(十五)css样式设置小技巧——上
    从零开始学习html(十四)单位和值
    从零开始学习html(十三) CSS代码缩写,占用更少的带宽
    从零开始学习html(十二)CSS布局模型——下
    从零开始学习html(十二)CSS布局模型——上
  • 原文地址:https://www.cnblogs.com/itzhoucong/p/14255117.html
Copyright © 2011-2022 走看看