这是我的第一篇CSDN博客。文章尽量保持原创性,但难免会引用到别人文章中的一些案例,文中会把引用的部分加以说明。
*****************************************************************
代理(Proxy)是Java中经常会用到的一种设计模式。代理模式的使用,可以在访问真实对象的前后,添加一些必要的行为,从而在不修改真实对象(类)的前提下,实现功能的扩展。
我们常见的java的代理模式有三种:静态代理,动态代理和Cglib代理。本文将以自己的理解来阐述一下前两种代理模式,重点是动态代理的实现。
我们以上网浏览为例,比如我们在国内要浏览"www.google.com.hk",因为访问受限,可能会需要一些翻墙软件之类的来代理上网, 我们先来设计一个通用的接口、真实类以及测试demo:
1. 定义一个IBrowser接口,只有一个抽象函数
public interface IBrowser {
public void browserURL(String url);
}
2.定义一个实现IBrowser接口的真实类
public interface IBrowser {
public void browserURL(String url);
}
3.测试demo:
public class TestBrowser {
public static void main(String[] args) {
IBrowser browser = new IBrowserImpl();
browser.browserURL("www.google.com.hk");
}
}
接下来我们要做的是再browser对象调用browserURL方法之前添加翻墙的操作,在调用完之后解除代理。在TestBrowser客户端添加显然是不合适的。我们先来说一下静态代理的实现:
一、静态代理:
静态代理的设计思路比较简单,设计一个代理类,同样实现IBrowser接口,因为代理类并不是自己去实现浏览功能,而只是在浏览前后添加一些代理的操作,浏览的动作还是需要真实类的对象去完成,所以需要传入一个真实类的对象。
public class ProxyBrowser implements IBrowser {
private IBrowser browser;
public ProxyBrowser(){}
// 传入一个IBrowserImpl对象,这个对象就是我们要代理的真实对象
public ProxyBrowser(IBrowser browser){
this.browser = browser;
}
public void browserURL(String url) {
// 在此添加翻墙操作*******
System.out.println("已成功翻墙");
// 通过传入的真实对象来调用browserURL方法
this.getBrowser().browserURL(url);
// 在此解除翻墙操作*******
System.out.println("已成功解除翻墙");
}
public IBrowser getBrowser() {
return browser;
}
public void setBrowser(IBrowser browser) {
this.browser = browser;
}
}
接下来修改我们的测试demo代码:
public class TestBrowser {
public static void main(String[] args) {
// 定义一个IBrowserImpl对象,向上转型为IBrowser类型
IBrowser browser = new IBrowserImpl();
// 将browser对象传入代理类的构造函数
ProxyBrowser proxy = new ProxyBrowser(browser);
proxy.browserURL("www.google.com.hk");
}
}
至此,静态代理的基本功能已经完成。但是我们会发现以下问题:
1.ProxyBrowser和IBrowserImpl实现了同样的接口,一旦接口发生改变,这两个类都要进行修改。
2.ProxyBrowser和IBrowserImpl高度耦合,ProxyBrowser已经很难再去扩展别的功能,换句话说,ProxyBrowser和IBrowserImpl已经静态绑定了。
为了克服以上问题,Java在J2SE1.3之后加入了java.lang.reflect.Proxy类,来协助实现动态代理的功能。