基本概念:
为其它对象提供一种代理以控制对这个对象的访问。 在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
上述说法有些抽象,其实跟跟买二手房要通过中介、 买股票要通过券商一样, 买卖双方要通过中介、券商交易, 即中间隔了一层, 这就是代理。
涉及的角色:
1、抽象角色:声明真实对象和代理对象的共同接口。
2、代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的借款以便在任何时刻都能够代替真实对象。
同事,代理对象可以对真实对象操作时,附加其它的操作,相当于对真实对象的封装。 (这里可以干坏事,比如雁过拔毛之类的)
3、真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。
静态代理:
public interface Shop {
public void buy(int count);
}
public class RealShop implements Shop {
private int mTotal; //总共有多少钱
public RealShop(int total) {
mTotal = total;
}
@Override
public void buy(int count) {
System.out.println("消费了" + count);
mTotal = mTotal - count;
}
}
public class ProxyShop implements Shop {
private Shop mShop; //指向被调用的对象
public ProxyShop(Shop shop) {
mShop = shop;
}
//代理模式写法
public void buy(int count) { //代理模式对引用对象有控制权, 即可以不调用原函数
if (count > 100) {
mShop.buy(count); //真正干活
} else {
//静态代理模式可以不调用被引用对象的方法
//但装饰者模式必须调用
}
//因为拿到了被调用对象的引用, 这里可以添油加醋!
mShop.buy(50); //雁过拔毛, 我拿到你的引用了,想干什么都可以!
}
//装饰者模式写法,
/*
public void buy(int count) {
mShop.buy(count); //真正干活
//do something
System.out.pringln("test"); //加点料就是装饰者模式的作用
}
*/
}
PS: 静态代理模式和装饰者模式基本一致, 唯一的区别在于代理模式有控制权, 可以不使用被引用对象。 装饰者模式必须调用被引用对象; 如上面例子中count>100的条件, 可以不调用引用对象的buy方法。动态代理:
使用InvocationHandler和Proxy在程序运行时替换实例。 每一个动态代理类都要实现InvocationHandler这个借口, 并且每个代理类的实例都关联到一个Handler, 当我们通过代理对象调用一个方法的时候, 这个方法的调用就会被转发为由InnovationHandler这个接口的invoke方法来进行调用。
public interface InvocationHandler {
/* Processes a method invocation on a proxy instance and returns the result. This method will be invoked on an invocation handler when a method is invoked on a proxy instance that it is associated with. */
public Object invoke(Object proxy, Method method, Object[] args)
}
实际验证, 在执行shop.buy(99)这条语句时, 执行了ShopHandler的invoke函数, 而不是RealShop的buy方法。
public static void main(String[] args) {
Shop realshop = new RealShop(1000);
InvocationHandler handler = new ShopHandler(realshop);
Shop shop = (Shop) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
realshop.getClass().getInterfaces(), handler);
System.out.println(shop.getClass().getName());
shop.buy(99); //消费99
}
public static class ShopHandler implements InvocationHandler {
private Object mObj; //要代理的真实对象
public ShopHandler(Object object) {
mObj = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before do something");
System.out.println("Method:" + method);
method.invoke(mObj, args);
System.out.println("after do something");
return null;
}
}
public interface Shop {
void buy(int count);
}
public static class RealShop implements Shop {
private int mTotal; //总共有多少钱
public RealShop(int total) {
mTotal = total;
}
@Override
public void buy(int count) {
System.out.println("do shop, buy:" + count);
mTotal = mTotal - count;
}
}
public static class ProxyShop implements Shop {
private Shop mShop; //指向被调用的对象
public ProxyShop(Shop shop) {
mShop = shop;
}
@Override
public void buy(int count) {
mShop.buy(count); //真正干活
//因为拿到了被调用对象的引用, 这里可以添油加醋!
mShop.buy(50); //雁过拔毛, 我拿到你的引用了,想干什么都可以!
}
}
com.sun.proxy.$Proxy0
before do something
Method:public abstract void com.example.MyClass$Shop.buy(int)
do shop, buy:99
after do something
从日志看出newProxyInstance返回的是com.sun.proxy.$Proxy0类对象。 在main函数里添加一行代码System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true")后重新编译。
查看buy函数, 实际上是调用的InnovationHandler的invoke方法。
参考:
https://blog.csdn.net/u011298387/article/details/53508709
https://blog.csdn.net/jiankunking/article/details/52143504