前言
代理模式也被称为委托模式,它是结构型设计模式的一种。在现实生活中我们用到类似代理模式的场景有很多,比如代理上网、打官司等。
定义
为其他对象提供一种代理以控制对这个对象的访问。
角色
- Subject:抽象主题类,声明真实主题与代理的共同接口方法。
- RealSubject:真实主题类,代理类所代表的真实主题。客户端通过代理类间接地调用真实主题类的方法。
- Proxy:代理类,持有对真实主题类的引用,在其所实现的接口方法中调用真实主题类中相应的接口方法执行。
- client:客户端类。
类型
从编码角度分类
- 静态代理
- 动态代理
从适用范围分类
-
远程代理:为一个对象在不同的地址空间提供局部代表,这样系统可以将
Server
部分的实现隐藏。 - 虚拟代理:使用一个代理对象表示一个十分耗资源的对象并在真正需要是才创建。
- 安全代理:用来控制真实对象访问的权限。一般用于真实对象有不同的访问权限时。
- 智能指引:当调用真实的对象时,代理处理另外一些事,比如计算机真实对象的引用计数,当该对象没有引用时,可以自动释放它;或者访问一个实际对象时,检查是否已经能够锁定它,以确保其他对象不能改变它。
静态代理模式的简单实现
场景描述
我多年没有回哈尔滨了,很想念哈尔滨的秋林红肠味道。但是本人因为工作一直很忙抽不开身,不能够亲自回哈尔滨购买,于是就拜托在哈尔滨的朋友帮我购买秋林红肠。
-
抽象主题类:抽象主题类具有真实主题类和代理的共同接口方法
buy
public interface IShop {
void buy();
}
-
真实主题类:这个购买者
Giants
就是我,实现了IShop
接口提供的buy
方法。
public class Giants implements IShop {
@Override
public void buy() {
System.out.println("购买");
}
}
-
代理类:我找的代理类同样也要实现
IShop
接口,并且要持有被代理者,在buy
方法中调用了被代理者的buy
方法。
public class Purchasing implements IShop {
private IShop mShop;
public Purchasing(IShop shop) {
this.mShop = shop;
}
@Override
public void buy() {
mShop.buy();
}
}
- 客户端类:客户端类的代码就是包含了真实主题类(被代理者),最终调用的都是真实主题类(被代理者)实现的方法。
public class Client {
public static void main(String[] args) {
IShop giants = new Giants();
IShop purchasing = new Purchasing(giants);
purchasing.buy();
}
}
动态代理模式的简单实现
场景描述
上面的例子是一个静态的代理,在代码运行前已经存在了代理类的
class
编译文件;而动态代理则是在带来运行时通过反射来动态地生成代理类的对象,并确定到底代理谁。我们在编码阶段无需知道代理谁,代理谁将会在代码运行时觉定。
- 创建动态代理类
/**
* 实现Java提供的动态代理接口 InvocationHandler ,实现该接口需要重写 invoke 方法
*/
public class DynamicPurchasing implements InvocationHandler {
private Object obj;
public DynamicPurchasing(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(obj, args);
if(method.getName().equals("buy")){
System.out.println("Giants在买买买");
}
return result;
}
}
- 修改客户端类代码如下:调用
Proxy.newProxyInstance
来生成动态代理类,调用purchasing
的buy
方法会调用mDynamicPurchasing
的invoke
方法。
public class Client {
public static void main(String[] args) {
//创建 Giants
IShop giants = new Giants();
//创建动态代理
DynamicPurchasing mDynamicPurchasing = new DynamicPurchasing(giants);
//创建 giants 的 ClassLoader
ClassLoader loader = giants.getClass().getClassLoader();
//动态创建代理类
IShop purchasing = (IShop) Proxy.newProxyInstance(loader, new Class[] {IShop.class}, mDynamicPurchasing);
purchasing.buy();
}
}
优点
- 真实主题类就是实现实际的业务逻辑,不用关心其他非本职工作。
- 真实主题类随时都会发生变化;但是因为它实现了公共的接口,所以代理类可以不做任何修改就能够使用。