设计模式(二)之委派模式(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; } } }
设计模式从来都是多个整合使用的
以上对委派模式的介绍到此结束,欢迎批评指正。 附:源码地址