代理模式初探
一.引入
本来就叫嚷着要学设计模式,目前就对MVC模式和单例模式有所了解,急不得;学J2SE时接触过观察者模式、门面模式和享元模式,那时候深感士兵哥牛X,现在依然,可以说没有他就没有现在该机构的辉煌(此处主要指知名度,不过对于培训机构来说,口碑就意味着一切)。最近几周一直在讲课,搞算法,昨天飞哥让研究下代理模式,我就看了下;学网络编程时该讲RMI框架(主要就是动态代理)了,结果没课了,我恨死学院了,就这样我只和张俊老师共同学习了七周。
本篇较少涉及RMI框架的动态代理,关键是我也不懂。
二.理论准备
代理模式的定义:对其他对象提供一种代理以控制对这个对象的访问,定义就凸显了代理模式的主要作用。在某些情况下,一个对象不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。代理模式的思想是为了提供额外的处理或者不同的操作而在实际对象与调用者之间插入一个代理对象。这些额外的操作通常需要与实际对象进行通信。
代理:一个角色代表别一个角色来完成某些特定的功能。 代理模式有三个角色: 1. 抽象主题角色 2. 代理主题角色 3. 实际被代理角色 其它类通过访问代理主题角色来访问实际被代理角色。
假设有一组对象都实现同一个接口,实现同样的方法,但这组对象中有一部分对象需要有单独的方法,传统的笨办法是在每一个应用端都加上这个单独的方法,但是代码重用性低,耦合性高。使用代理模式创建代理对象,让代理对象控制目标对象的访问(目标对象可以是远程的对象、创建开销大的对象或需要安全控制的对象),并且可以在不改变目标对象的情况下添加一些额外的功能。
三.生活来源
- 现实世界中,秘书就相当于一个代理,老板开会,那么通知员工开会时间、布置会场、会后整理会场等等开会相关工作就可以交给秘书做,老板就只需要开会就行了,不需要亲自做那些事。同理,在我们程序设计中也可使用代理模式来将由一系列无关逻辑组合在一起的代码进行解耦合,比如业务代码中的日志代码就可以在代理中进行。Spring的AOP就是典型的动态代理应用。
- 过年加班比较忙,没空去买火车票,这时可以打个电话到附近的票务中心,叫他们帮你买张回家的火车票,当然这会附加额外的劳务费。但要清楚票务中心自己并不卖票,只有火车站才真正卖票,票务中心卖给你的票其实是通过火车站实现的。这点很重要!
- 比如生产商,中间商,客户这三者这间的关系 客户买产品并不直接与生产商打交道,也不用知道产品是如何产生的,客户只与中间商打交道,而中间商就可以对产品进行一些包装,提供一些售后的服务。
可以看出代理模式主要使用了java的多态,干活的是被代理类,代理类主要是接活,你让我干活,好,我交给幕后的类去干,你满意就成,那怎么知道被代理类能不能干呢?同根就成,大家知根知底,你能做啥,我能做啥都清楚得很,同样一个接口呗,网络牛人随口一说就是经典,呵呵。
四.Java实现
package edu.hpu.designpattern;
//抽象主题角色
public interface Talk {public void talk(String msg);}package edu.hpu.designpattern;
//实际被代理角色
public class People implements Talk{String name;String msg;public String getName() {
return name;
}public String getMsg() {
return msg;
}public People(String name, String msg) {
super();
this.name = name;
this.msg = msg;
}@Overridepublic void talk(String msg) {System.out.println(msg);}public void talk() {System.out.println(this.msg);
}}package edu.hpu.designpattern;
//代理主题角色
public class TalkProxy implements Talk{Talk talker;//传递接口的实现类
public TalkProxy(Talk talker) {
super();
this.talker = talker;
}@Overridepublic void talk(String msg) {//并不知道如何具体talk
talker.talk(msg);}public void sing(String song) {System.out.println("唱歌:"+song);
}}package edu.hpu.designpattern;
public class ProxyTest {public static void main(String[] args) {//接口不能new,不过可以new实现类,或者按内部类形式
Talk talk = new People("Tom","Tom说的话");//由于是接口类型,所以必须调用实现的接口方法,不能是重写的方法(无参数),否则编译错误
talk.talk("实现类说话");
/*
* 只能传递实现类,若是直接接口的话,由于不可new,编译器报错说可能未初始化*/TalkProxy tp = new TalkProxy(talk);
tp.talk("代理类说话");
tp.sing("伤心太平洋");
}}五.实际应用
参考资料:http://blog.csdn.net/jackiehff/article/details/8621517
(1)远程代理(Remote Proxy) :可以隐藏一个对象存在于不同地址空间的事实。也使得客户端可以访问在远程机器上的对象,远程机器可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求。
(2)虚拟代理(Virtual Proxy) :允许内存开销较大的对象在需要的时候创建。只有我们真正需要这个对象的时候才创建。
(3)写入时复制代理(Copy-On-Write Proxy) :用来控制对象的复制,方法是延迟对象的复制,直到客户真的需要为止,本质是虚拟代理。(4)保护代理(Protection (Access)Proxy) :为不同的客户提供不同级别的目标对象访问权限 。
(5)缓存代理(Cache Proxy) :为开销大的运算结果提供暂时存储,它允许多个客户共享结果,以减少计算或网络延迟。
(6)防火墙代理(Firewall Proxy) :控制网络资源的访问,保护主题免于恶意客户的侵害。
(7)同步代理(SynchronizationProxy) :在多线程的情况下为主题提供安全的访问。
(8)智能引用代理(Smart ReferenceProxy) :当一个对象被引用时,提供一些额外的操作,比如将对此对象调用的次数记录下来等。
(9)复杂隐藏代理(Complexity HidingProxy) :用来隐藏一个类的复杂集合的复杂度,并进行访问控制。有时候也称为外观代理(Façade Proxy),这不难理解。复杂隐藏代理和外观模式是不一样的,因为代理控制访问,而外观模式是不一样的,因为代理控制访问,而外观模式只提供另一组接口。六.动态代理
Java动态代理类位于Java.lang.reflect包下,一般主要涉及到以下两个类:
(1) Interface InvocationHandler
(2) Proxy:该类即为动态代理类