代理模式
平时我们生活中的代理,是指类似中介的角色,能够代理某一公司或机构帮助我们完成一类事情,同理,代码世界中的代理模式,也差不多是这样,先来看一下代理模式的类图:
上面的Subject是一个公有接口,提供了一系列的能力,比如,房产公司就是一个公有接口,提供了房产交易的功能。
Proxy可以认为是房产中介,实现了Subject接口,也就是说 Proxy代理了Subject,房产中介需要知道具体客户的信息,所以Proxy内部需要维护一个RealSubject。
RealSubject则是购房者,也实现了Subject接口。(为什么购房者需要实现一个房产公司接口呢?可以理解为,购房者需要和房产公司建立了联系,才能进行房产买卖,至于买卖方式,是分期还是全款,是线上支付还是线下支付,这个看具体的购房者)
下面是示例代码:
EstateCompany类(代表Subject公有接口):
public interface EstateCompany {
void tradeRealEstate();
}
RealCustomer类(代表RealSubject):
public class ReealCustomer implements EstateCompany{
private String name;
public ReealCustomer(String name) {
this.name = name;
// TODO Auto-generated constructor stub
}
@Override
public void tradeRealEstate() {
// TODO Auto-generated method stub
System.err.println(name+"去银行取了五百万买房");
}
}
ProxyWorker类(代表 Proxy):
public class ProxyWorker implements EstateCompany{
private ReealCustomer mCustomer;
public void setmCustomer(EstateCompany realEstateCompany) {
this.mCustomer = (ReealCustomer) realEstateCompany;
}
@Override
public void tradeRealEstate() {
// TODO Auto-generated method stub
System.err.println("中介想办法找客户");
mCustomer.tradeRealEstate();
System.err.println("办理相关手续,成交了一套房子 ");
}
}
Client类:
public class Client {
public static void main(String[] args) {
ReealCustomer customer = new ReealCustomer("陈先生");
ProxyWorker proxyWorker = new ProxyWorker();
proxyWorker.setmCustomer(customer);
proxyWorker.tradeRealEstate();
}
}
运行Client,得到日志:
至此,就是一个Java静态代理模式的运用。这样做的好处是什么呢?个人理解,是可以解耦。从上面Client调用时就可看到,只需要给ProxyWorker设置一个Customer,再调用tradeRealEstate,就可以完成房产交易,在调用的地方是看不到交易的细节的。交易细节很好地被隐藏了,而且ProxyWorker还可以扩展一些功能。
静态代理也有以下缺点:比如在上述例子中,想给EstateCompany增加一个积分返现的方法,那么,实现了该接口的所有类都要做出修改。
再者,代理类也会比较多,比如ProxyWorkerA只能卖南山区的房子,ProxyWorkerB只能卖罗湖区的房子,ProxyWorkerC只能卖福田区的房子,那为了客户可以随时看房子,房产公司就要先雇佣ProxyWorkerA、ProxyWorkerB、ProxyWorkerC,假如一直没有客户,岂不是浪费成本?有哥们可能会说,直接把ProxyWorkerA、ProxyWorkerB、ProxyWorkerC的功能写在一个ProxyWorker里不可以吗,当然可以,只不过这样ProxyWorker里的代码就会比较多,而且可能有较多重复代码,这样肯定不是一个比较好的做法。
把类写简洁,一般就意味着类要多点,但是又不想接口类写得太多造成所谓类爆炸,这,有点强人所难啊。。。
这时,一个牛逼的代理出现了,他说,根本不需要请三个代理,我可以在客户需要ProxyWorkerA的时候化身ProxyWorkerA,在客户需要ProxyWorkerB的时候化身ProxyWorkerB。公司出了新政策和有什么活动要搞,你不用再费力气去分别通知三个代理了,你只需要通知客户就可以了,连我都不需要通知,我自己有办法知道这些政策和活动。
这个牛逼的代理就是动态代理。下面来看示例代码:
EstateCompany类:
public interface EstateCompany {
void tradeRealEstate();
}
ReealCustomer类:
public class ReealCustomer implements EstateCompany{
private String name;
public ReealCustomer(String name) {
this.name = name;
// TODO Auto-generated constructor stub
}
@Override
public void tradeRealEstate() {
// TODO Auto-generated method stub
System.err.println(name+"去银行取了五百万买房");
}
}
ProxyFactory类取代了ProxyWorker类:
public class ProxyFactory{
private Object target;
public ProxyFactory(Object target){
this.target=target;
}
//获取罗湖区的代理对象
public Object getLuoHuProxy(){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("先去看看罗湖区的房子");
//执行目标对象方法
Object returnValue = method.invoke(target, args);
System.out.println("成交了罗湖区的一套房子");
return returnValue;
}
}
);
}
//获取福田区的代理对象
public Object getFuTianProxy(){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("先去看看福田区的房子");
//执行目标对象方法
Object returnValue = method.invoke(target, args);
System.out.println("成交了福田区的一套房子");
return returnValue;
}
}
);
}
}
Client类:
public class Client {
public static void main(String[] args) {
ReealCustomer customer = new ReealCustomer("陈先生");
EstateCompany object = (EstateCompany) new ProxyFactory(customer).getLuoHuProxy();
object.tradeRealEstate();
}
}
打印结果:
可以看到,在client中,已经无需创建ProxyWorker类,如果需要增加看光明区的房子的代理,只需要在 ProxyFactory中增加一个getGuangmingProxy(),在该方法中做相应逻辑并返回Object即可,
而且EstateCompany接口有修改,只需要在ReealCustomer中修改即可,不需要修改ProxyFactory。
值得注意的是,ProxyFactory下图中箭头所指方法不是顺序执行的,它们执行的顺序是随机的
比如,也可以得到如下结果: