1 模式定义
指具有与被代理对象相同的接口(此处的接口是指:方法)的类,客户端必须通过【代理类】来间接的与【被代理目标类】进行交互,
2 应用场景
一般是因为客户端不想直接访问实际的对象,或者访问实际的对象存在困难,因此通过一个代理对象来完成间接的访问。
3 组成部分
- Subject【抽象对象角色】 : 声明了目标对象和代理对象的共同接口/父类【动态代理只能是接口】。该类可以是一个抽象类也可以是一个接口
- RealSubject【委托对象\目标对象\被代理对象】 : 代理对象所要代表的目标对象。
- ProxySubject【代理对象】 : 代理对象内部含有委托对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口(此处接口是指:方法,如Visit方法),以便可以在任何时候替代目标对象。
从UML图中,可以看出代理类[ProxySubject]与真正实现的类[RealSubject]都是继承了抽象的主题类[Subject],这样的好处在于代理类可以与实际的类有相同的方法,可以保证客户端使用的透明性
3.2模式分类
代理模式可以有两种实现的方式:
- 静态代理,
- 另一种是各大框架都喜欢的动态代理。如果你的代理类【RealSubject】存在很多,不方便用静态实现,就可以使用动态代理
两者的区别:动态代理和静态代理的区别就是动态代理不用我们去手动编写代理类。动态代理就是JDK提供的机制,可在内存中动态的生成代理类。
4 场景说明
海外代购,如你现在需要购某一个定制包包,而这包只有国外某专卖店里才有卖,可这段时间你抽不出时间去海外,这时你可以找到专业的海外代购人士,如他们帮你代购回来,
5 示例代码:
5.1 静态代理
5.1.1 Subject.java
package proxy;
public interface Subject {
public void shopping();
}
5.1.2 RealSubject.java
public class RealSubject implements Subject {
@Override
public void shopping() {
// TODO Auto-generated method stub
System.out.println("RealSubject::shopping");
}
}
5.1.3 ProxySubject.java
public class ProxySubject implements Subject {
private RealSubject mRealSubject;
public ProxySubject(RealSubject mRealSubject){
this.mRealSubject = mRealSubject;
}
@Override
public void shopping() {
// TODO Auto-generated method stub
mRealSubject.shopping();
}
}
5.1.4 ClientProxy
public class ClientProxy {
public static void main(String[] args) {
RealSubject mReal = new RealSubject();
ProxySubject mProxy = new ProxySubject(mReal);
mProxy.shopping();
}
}
5.1.5 输出打印
通过上面的代理代码,我们可以看出代理模式的特点,代理类接受一个Subject接口的对象(可以任何实现该接口的对象),都可以通过代理类进行代理,增加了通用性。但是也有缺点,每一个代理类都必须实现一遍委托类(也就是realsubject)的接口,如果接口增加方法,则代理类也必须跟着修改。其次,代理类每一个接口对象对应一个委托对象,如果委托对象非常多,则静态代理类就非常臃肿,难以胜任。
5.2 动态代理
动态代理是实现方式,是通过反射来实现的,借助Java自带的java.lang.reflect.Proxy
,通过固定的规则生成。
其步骤如下:
- 编写一个委托类的接口,即静态代理的(Subject接口)
- 实现一个真正的委托类,即静态代理的(RealSubject类)
- 创建一个动态代理类,实现
InvocationHandler
接口,并重写该invoke
方法 - 在测试类中,生成动态代理的对象。
第一二步骤,和静态代理一样,不过说了。第三步,代码如下:
//创建一个动态代理类,实现InvocationHandler接口,并重写该invoke方法
public class DynamicProxy implements InvocationHandler {
private Object mObject;
public DynamicProxy (Object mObject){
this.mObject = mObject;
}
@Override
public Object invoke(Object arg0, Method arg1, Object[] arg2)
throws Throwable {
// TODO Auto-generated method stub
return arg1.invoke(mObject, arg2);
}
}
第四步,创建动态代理的对象
public class ClientProxy {
public static void main(String[] args) {
//(1)静态代理
//RealSubject mRealSubject = new RealSubject();
//ProxySubject mProxy = new ProxySubject(mRealSubject);
//mProxy.shopping();
//(2)动态代理
Subject mReal = new RealSubject();
DynamicProxy proxy = new DynamicProxy(mReal);
ClassLoader loder = mReal.getClass().getClassLoader();
Subject object = (Subject)Proxy.newProxyInstance(loder, new Class[]{Subject.class}, proxy);
object.shopping();
}
}
创建动态代理的对象,需要借助Proxy.newProxyInstance
。该方法的三个参数分别是:
- ClassLoader loader表示当前使用到的appClassloader。
- Class<?>[] arg1表示目标对象实现的一组接口。
- InvocationHandler arg2表示当前的InvocationHandler实现实例对象。\
6 小结
静态代理与装饰模式差不多 ^-^
Android源码模式分析:
待续
站在巨人的肩膀 参考文献:
https://www.cnblogs.com/qifengshi/p/6566752.html