当前位置: 首页 > 后端技术 > Java

你觉得委托模式很神秘,其实你每天都在用

时间:2023-04-01 13:53:02 Java

本文节选自《设计模式就该这样学》1 使用委托模式模拟任务分配场景我们用代码模拟老板给员工分配任务的业务场景。首先创建IEmployee员工界面。publicinterfaceIEmployee{voiddoing(Stringtask);}创建员工EmployeeA类。公共类EmployeeA实现IEmployee{protectedStringgoodAt="programming";publicvoiddoing(Stringtask){System.out.println("我是员工A,我擅长"+goodAt+",现在开始做"+task+"工作");}}创建员工EmployeeB类。publicclassEmployeeBimplementsIEmployee{protectedStringgoodAt="平面设计";publicvoiddoing(Stringtask){System.out.println("我是员工B,我擅长"+goodAt+",现在开始做"+task+"工作");}}创建ProjectManagerLeader类。publicclassLeaderimplementsIEmployee{privateMapemployee=newHashMap();publicLeader(){employee.put("爬虫",newEmployeeA());employee.put("海报图",newEmployeeB());}publicvoiddoing(Stringtask){if(!employee.containsKey(task)){System.out.println("Thistask"+task+"beyondmyability");返回;}employee.get(task).doing(任务);}}然后创建一个Boss类来发号施令。publicclassBoss{publicvoidcommand(Stringtask,Leaderleader){leader.doing(task);}}最后写客户端测试代码。公共类测试{publicstaticvoidmain(String[]args){newBoss().command("Poster",newLeader());newBoss().command("爬虫",newLeader());newBoss().command("卖手机",newLeader());}}通过上面的代码,我们形象地还原了老板分配任务的业务场景,这也是委托模型的生动体现。其类图如下图所示。2 JDK源码应用中的委托模式JDK中有一个典型的委托。众所周知,JVM在加载类时采用双亲委派模型。这是什么?当一个类加载器加载一个类时,它首先将请求委托给它的父类加载器来执行。如果父类加载器还有父类加载器,继续向上委托,直到顶层启动类加载器;如果父类加载器能够完成类加载,则返回成功;如果父类加载器无法完成加载,则子类加载器尝试加载自己。从定义中可以看出,双亲委托加载的类加载器加载类时,并不是自己先加载,而是委托给父类加载器。我们看一下loadClass()方法的源码,它在ClassLoader中。在这个类中定义了一个父类,用于后面的类加载。publicabstractclassClassLoader{...privatefinalClassLoaderparent;...protectedClassloadClass(Stringname,booleanresolve)throwsClassNotFoundException{synchronized(getClassLoadingLock(name)){Classc=findLoadedClass(name);}如果(c==null){longt0=System.nanoTime();try{if(parent!=null){c=parent.loadClass(name,false);}else{c=findBootstrapClassOrNull(名称);}}catch(ClassNotFoundExceptione){}if(c==null){longt1=System.nanoTime();c=findClass(名字);sun.misc.PerfCounter.getParentDelegationTime().addTime(t1-t0);sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);sun.misc.PerfCounter.getFindClasses().increment();}}如果(解决){resolveClass(c);}返回c;}}...}同样,在Method类中,常用的代理执行方法invoke()也有类似的机制,代码如下,InvocationTargetException{if(!override){if(!Reflection.quickCheckMemberAccess(clazz,modifiers)){Class调用者=Reflection.getCallerClass();checkAccess(调用者、clazz、obj、修饰符);}}MethodAccessorma=methodAccessor;//读取volatileif(ma==null){ma=acquireMethodAccessor();}returnma.invoke(obj,args);}看完代码,相信小伙伴们已经弄清楚委托模式和代理模式的区别了。3 委托模式在Spring源码中的应用下面看一下委托模式在Spring中的应用。SpringIoC模块中的DefaultBeanDefinitionDocumentReader类将设置BeanDefinitionParserDelegate类型的Delegate对象传递给this.delegate,并将此对象作为参数传递给parseBeanDefinitions(root,this.delegate)。主要的解析工作由delegate为主完成,代码如下。protectedvoidparseBeanDefinitions(Elementroot,BeanDefinitionParserDelegatedelegate){//判断节点是否属于同一个命名空间,如果是则进行后续解析if(delegate.isDefaultNamespace(root)){NodeListnl=root.getChildNodes();for(inti=0;ihandlerMapping=newHashMap();@Overrideprotectedvoidservice(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{doDispatch(req,resp);}privatevoiddoDispatch(HttpServletRequestreq,HttpServletResponseresp){Stringurl=req.getRequestURI();方法method=handlerMapping.get(url);//此处省略反使用方法的代码...}@Overridepublicvoidinit()throwsServletException{try{handlerMapping.put("/web/getMemeberById.json",MemberController.class.getMethod("getMemberById",new类[]{String.class}));}catch(Exceptione){e.printStackTrace();}}}配置web.xml文件。WebApplicationdelegateServletcom.tom.pattern.delegate.mvc。DispatcherServlet1delegateServlet/*这样就实现了一个完整的委托模式。当然,Spring中还有很多使用委托模式的情况,通过命名就可以识别。在Spring源码中,只要以Delegate结尾,就是实现了委托模式。比如BeanDefinitionParserDelegate根据不同的类型委托不同的逻辑去解析BeanDefinition。关注微信公众号“汤姆炸弹架构”回复“设计模式”获取完整源码。【推荐】汤姆炸弹架构:收藏本文相当于收藏一本《设计模式》书本文为《汤姆炸弹架构》原创,转载请注明出处。科技在于分享,我分享我的快乐!如果本文对您有帮助,请关注并点赞;有什么建议也可以留言或私信。您的支持是我坚持创作的动力。关注微信公众号“汤姆炸弹架构”,获取更多技术干货!