委派模式(Delegate)

委派模式(Delegate)

概述:

  委派模式不属于 23 种设计模式之一, 是面向对象设计模式中常用的一种模式。
  这种模式的原理为类 B和类 A 是两个互相没有任何关系的类, B 具有和 A 一模一样的方法和属性; 并且调用 B 中的方法,就是调用 A 中同名的方法和属性。 B 好像就是一个受 A 授权委托的中介。 第三方的代码不需要知道 A 的存在, 也不需要和 A 发生直接的联系, 通过 B 就可以直接使用 A 的功能, 这样既能够使用到 A 的各种功能, 又能够很好的将 A 保护起来了, 一举两得。

穷举法:

  平时工作中的场景就用到了委派模式。
  项目经理是BOSS和员工之间的一个中介。
  项目经理:在老板眼里,他负责干活,实际上只负责类似于调度的工作,分配任务。
  重要特征:项目经理分配任务之前,他要做一个权衡(选择),类似于策略模式。
委派模式(Delegate)
针对上述场景写段小代码:
客户请求(Boss)、委派者(Leader)、被被委派者(Target)

老板类

//老板下达命令:"登陆!"给项目经理。
public class Boss {
	
    public static void main(String[] args) {
    	//委派这要持有被委派者的引用
        new Leader().doing("登录");
    }
    
}

工作人员接口

public interface ITarget {

    public void doing(String command);

}

项目经理类

public class Leader implements  ITarget {

    private Map<String,ITarget> targets = new HashMap<String,ITarget>();
	
	//员工A擅长做“加密”任务;员工B擅长做“登陆”任务
    public Leader() {
        targets.put("加密",new TargetA());
        targets.put("登录",new TargetB());
    }

    //项目经理自己不干活
    public void doing(String command){
        targets.get(command).doing(command);
    }

}

员工A

public class TargetA implements ITarget {
    @Override
    public void doing(String command) {
        System.out.println("我是员工A,我现在开始干" + command + "工作");
    }
}

员工B

public class TargetB implements  ITarget {
    @Override
    public void doing(String command) {
        System.out.println("我是员工B,我现在开始干" + command + "工作");
    }
}

运行结果如下:

委派模式(Delegate)

实际应用场景

  Spring中用到了很多委派模式,下面我们就来说受最常见的ServletDispatcher。源代码这里暂时先不上,会在Spring源码分析中再研究。先看思路。
  大家是否还记得这样的写法?

<servlet>
    <servlet-name>aaa</servlet-name>
    <servlet-class>com.gupaoedu.XxxServlet</servlet-class>
</servlet>

<servlet-pattern>
        <servlet-name>aaa</servlet-name>
        <servlet-url>/web/xxx.do</servlet-url>
</servlet-pattern>

  是的,在使用ServletDispatcher之前,我们是通过web.xml使得每个url对对应一个Serlvet(url由浏览器输入)。

模拟ServletDispatcher类

public class ServletDispatcher {

    private List<Handler> handlerMapping = new ArrayList<Handler>();

    public ServletDispatcher(){
        try {
            Class<?> memberActionClass = MemberAction.class;
            //将uri与调用方法之间的关系存入handlerMapping中
            handlerMapping.add(new Handler()
                    .setController(memberActionClass.newInstance())
                    .setMethod(memberActionClass.getMethod("getMemberById", new Class[]{String.class}))
                    .setUrl("/web/getMemberById.json"));
        }catch(Exception e){

        }
    }

    public void doService(HttpServletRequest request, HttpServletResponse response){
        doDispatch(request,response);
    }


    private void doDispatch(HttpServletRequest request, HttpServletResponse response){

        //1、获取用户请求的url
        //   如果按照J2EE的标准、每个url对对应一个Serlvet,url由浏览器输入
       String uri = request.getRequestURI();

        //2、Servlet拿到url以后,要做权衡(要做判断,要做选择)
        //   根据用户请求的URL,去找到这个url对应的某一个java类的方法

        //3、通过拿到的URL去handlerMapping(我们把它认为是策略常量)
        Handler handle = null;
        for (Handler h: handlerMapping) {
            if(uri.equals(h.getUrl())){
                handle = h;
                break;
            }
        }

        //4、将具体的任务分发给Method(通过反射去调用其对应的方法)
        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执行的结果,通过Response返回出去
//        response.getWriter().write();

    }

	//此内部类相当于实体类Handler
    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;
        }
    }


}

MemberAction类,相当于Controller控制层中的类。

public class MemberAction {

    public void getMemberById(String mid){}

}

  综上,委派者是浏览器的访问者,ServletDispatcher相当于被委派者,通过HandlerMapping实现了url与调用方法的 一 一对应。

委派模式与代理模式、策略模式的比较

  • 委派模式相当于静态代理一种非常特殊的情况,全权代理;
  • 被委派这分配任务的时候,类似于策略模式;
  • 代理模式注重的是过程,委派模式注重的是结果;
  • 策略模式注重是可扩展(外部扩展),委派模式注重内部的灵活和复用
  • 委派模式的核心:分发、调度、派遣。委派模式就是静态代理和策略模式一种特殊的组合。
上一篇:C#进阶学习第十二天


下一篇:谷歌浏览器的源码分析 6