委派模式(Delegate)
概述:
委派模式不属于 23 种设计模式之一, 是面向对象设计模式中常用的一种模式。
这种模式的原理为类 B和类 A 是两个互相没有任何关系的类, B 具有和 A 一模一样的方法和属性; 并且调用 B 中的方法,就是调用 A 中同名的方法和属性。 B 好像就是一个受 A 授权委托的中介。 第三方的代码不需要知道 A 的存在, 也不需要和 A 发生直接的联系, 通过 B 就可以直接使用 A 的功能, 这样既能够使用到 A 的各种功能, 又能够很好的将 A 保护起来了, 一举两得。
穷举法:
平时工作中的场景就用到了委派模式。
项目经理是BOSS和员工之间的一个中介。
项目经理:在老板眼里,他负责干活,实际上只负责类似于调度的工作,分配任务。
重要特征:项目经理分配任务之前,他要做一个权衡(选择),类似于策略模式。
针对上述场景写段小代码:
客户请求(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 + "工作");
}
}
运行结果如下:
实际应用场景
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与调用方法的 一 一对应。
委派模式与代理模式、策略模式的比较
- 委派模式相当于静态代理一种非常特殊的情况,全权代理;
- 被委派这分配任务的时候,类似于策略模式;
- 代理模式注重的是过程,委派模式注重的是结果;
- 策略模式注重是可扩展(外部扩展),委派模式注重内部的灵活和复用
- 委派模式的核心:分发、调度、派遣。委派模式就是静态代理和策略模式一种特殊的组合。