分析代理模式

        学过设计模式,用过设计模式,可是转瞬又忘了,这些模式究竟是什么,究竟是干什么用,究竟是用在哪里的.DRP的时候,又介绍了代理模式,介绍了静态代理,动态代理;当时就认为代理模式,就像是在client和真实的主题类中加了一个隔层,就像是解耦,加了一个中间层.

       之前学习的时候,感觉那个样例举得不好,我一直不明确为什么要用代理.他的样例说了一个人小明要追小美,可是小明拜托小代去帮忙追小美,给小美送礼物,最后小美喜欢上小代了.当时认为,小明个二货,追人还要找代理,最后人財两空.事实上,全然能够不用代理,自己出马的.

        后来发现,代理,现实中非常多都须要用到代理的,有的甚至是必须使用代理.比方明星,你要找他们办事,他们就会让你去找他的经纪人,经纪人就是代理;打官司,须要律师,律师就是代理;你家生产了非常多产品,可是不想自己去卖,交由销售商去卖,销售商就是代理;还有上网翻墙的时候,使用代理,能够使用静态代理,你明白的指定随意一个,或者使用动态代理,他自己决定用哪个,你无论,仅仅要能上网就成.所以说,代理的运用是相当广泛的.

        那个时候学习的代理模式,类图就是例如以下所看到的.有一个client,一个接口Subject,接口中有一个方法request().还有两个类,代理类和实际对象类来实现这个接口,这样他们就有共同的行为了,能够在不论什么使用实际对象类的地方使用代理了.

        如之前的小明追小美.小明是RealSubject,小吕是ProxySubject,而送礼物是Subject的接口,里面的request()方法能够是送各种东西.那么因为小明和小代都实现了送礼物的接口,所以里面的送各种礼物的方法他们都有.所以,都能够给小美送礼物.而因为小代是代理小明去送礼物的,所以实际小代送给小美的礼物,都是从小明那里拿的.送给小美的不论什么礼物都是小明要送给小美的.


         事实上代理模式除了能提供取代功能,还能够提供一些附加功能.如在学习DRP的时候,分析了静态代理和动态代理.他介绍了你能够在代理模式的代理类中加入信息打印,在调用打印前,在调用后打印,调用成功打印,这样就能够加入日志记录的功能,而不影响他们实际的类.这就能够做到对改动关闭,对加入开放.

         就例如以下图的时序图显示的,在client调用代理的addUser()方法,代理的该方法能够打印输入參数,然后再去调用实际对象的addUser()方法,然后在加入完毕之后打印成功失败信息,最后返回结果.你在代理类中还能够做非常多事,而实际对象类仅仅要写最关键的addUser()的代码,其它不用管.这也是单一职责的体现.

       可是就如同图中所说的,这种代理尽管非常有优点,可是一个实际对象类相应一个代理类,那么类就太多了.并且这些代理类的方法可能会大量反复,而反复的代码最好不要出现多次.所以一个好的方法就是把这些反复的方法,提取出来,能够试试用泛型.

        可是实际Java他们已经考虑到这个问题,所以提供了动态代理.

        动态代理的类图是这种,他和静态代理的类图的差别就是图中的Proxy已经不是我们自己写的一个代理类了,而是java他自己提供的一个Proxy,他是动态代理类.你能够依据实际对象类的情况,Proxy的静态方法newProxyInstance()获得对应的实际对象的代理,所以这个代理类代理的是哪个类,仅仅有在执行的时候才干知道.

       所以在实际对象类和代理中,他们没有直接的关系了,不用代理再指向实际对象.而他们之间的关系由InvocationHandler(调用处理器)来维护,而这个InvocationHandler的类必须实现InvocationHandler的接口.仅仅要实现了这个接口,类名爱叫啥叫啥.

      而为什么InvocationHandler来维护他们的关系,他有什么优势?InvocationHandler的作用是响应代理的不论什么调用.当client调用代理的时候,代理就会找InvocationHandler,要他去实现client的请求,InvocationHandler调用的Invoke方法,再去调用实际对象类的实际方法.

      注意InvocationHandlerinvoke方法,无论你Proxy动态代理类被调用的是什么方法,对于调用处理器他被调用的仅仅有invoke.以不变应万变,无论你来的是什么对我来说都是invoke,我统一处理了就好.


         再看一下动态代理的时序图,下图中的jdk代理类就是上图中的Proxy,LogHandler对象就是InvocationHandler,UserManageImpl就是RealSubject.

        client调用jdk代理类的findUserById()方法,而代理立刻调用LogHandlerinvoke方法,invoke方法中也和之前一样打印了一些信息,而且调用了实际对象的findUserById()方法,来返回实际的结果.


         两幅时序图的差别就是,中间原本的UserManagerImplProxy的代理类被jdk代理类和LogHandler替换了.在静态代理中,须要明白指明代理类是谁,代理的是哪个实际对象类;而在动态代理类中的,则用jdk代理类和LogHandler,来依据实际情况来得到实际的代理类.

        jdk代理类能够依据传递过来的參数生成相应的代理,而生成的代理,会有实际对象的全部方法,你调用这些方法的随意方法,都会去找LogHandlerinvoke()方法,invoke方法的參数也会告诉他,他要去找哪个类,找哪个方法,用哪些參数,然后就能够动态的调用方法了

       这样就仅仅用一份代码,能够创建全部须要的代理类.

       写完了,认为还是不大了解,仅仅有真正了解,才干真正正确的运用.最后总结一下,用静态代理,符合了单一职责,和开放封闭原则,可是代理类太多,代码反复;动态代理,攻克了这些问题,仅仅用一份代码,就能够创建无数代理类,缺点是效率低.并且代理模式能够使RealSubject类中的方法的功能更单一,由于用代理,能够将与功能无关的代码都写到invoke方法中,那么以后要维护RealSubject类也是非常方便的.

原文地址:https://www.cnblogs.com/mfrbuaa/p/3939835.html