代理模式的定义
为其他对象提供一种代理以控制这个对象的访问。代理对象起到中介作用,可去掉功能服务或增加额外的功能。
代理的设计理念:限制对象的直接访问。不能通过 new 的方式得到想要的对象,而是访问该对象的代理类。这样的话,我们就保护了内部对象,如果有一天内部对象因为某个原因换了个名或者换了个方法字段等等,那对访问者来说一点不影响,因为他拿到的只是代理类而已,从而使该访问对象具有高扩展性。然而,代理类可以实现拦截方法,修改原方法的参数和返回值,满足了代理自身需求和目的,也就是是代理的方法增强性。
代理模式 UML
Subject(抽象角色):声明真实对象和代理对象的共同接口;
ProxySubject(代理角色):代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
(RealSubject)真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。调用 RealSubject 的方法,都要经过 ProxySubject 进行代理。
种类
静态代理
静态代理模式的实现
-
抽象一个接口 ISubject(抽象主题):声明真实主题与代理的共同接口方法
-
实现该接口 RealSubject(真实主题):定义了代理所表示的真实对象,由其执行具体的业务逻辑方法,而客户类则通过代理间接地调用真实主题中定义的方法
-
创建代理对象类 ProxySubject(代理类):持有一个对真实主题类的引用,在其所实现的接口方法中调用真实主题类中相应的接口方法执行,以此起到代理的作用
-
客户端发起调用(客户类)
1.抽象一个接口 ISubject(抽象主题)
public interface ISubject {
void doAction(String action);
}
2.实现该接口 RealSubject(真实主题)
public class RealSubject implements ISubject {
public void doAction(String action) {
// TODO Auto-generated method stub
Log.e("TAG", "I am RealSubject, do action "+ action);
}
}
3.创建代理对象类 ProxySubject(代理类)
public class ProxySubject implements ISubject {
ISubject mRealSubject;
public ProxySubject(ISubject mRealSubject) {
super();
this.mRealSubject = mRealSubject;
}
public void doAction(String action) {
// TODO Auto-generated method stub
preRequest();
mRealSubject.doAction(action);
postRequest();
}
protected void postRequest() {
// TODO Auto-generated method stub
Log.e("TAG", "postRequest");
}
protected void preRequest() {
// TODO Auto-generated method stub
Log.e("TAG", "preRequest");
}
}
4.客户端发起调用(客户类)
private static void testStatical() {
RealSubject realSubject = new RealSubject();
ProxySubject proxySubject = new ProxySubject(realSubject);
proxySubject.doAction("play");
}
5.将会看到以下 log
preRequest
I am RealSubject, do action play
postRequest
动态代理
动态代理是指在运行时动态生成代理类。不需要我们像静态代理那个去手动写一个个的代理类。生成动态代理类有很多方式:Java动态代理,CGLIB,Javassist,ASM库等
动态代理模式的实现
实现步骤
-
创建 ISubject
-
实现 RealSubject
-
通过 Proxy.newInstance 生成动态代理对象
public class DynamicProxyHandler implements InvocationHandler {
private Object target;
public DynamicProxyHandler(Object target) {
this.target = target;
}
//该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象
public <T> T getProxy() {
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
// 该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象
// 第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Log.e("TAG", "办事之前先收取点费用");
Log.e("TAG", "开始办事");
Object result = null;
try {
result = method.invoke(target, args);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.e("TAG", "办完了");
return result;
}
}
-
客户端调用
ISubject subject = new RealSubject();
ISubject proxy = new DynamicProxyHandler(subject).getProxy();
proxy.doAction("play");
最终将输出以下 log
办事之前先收取点费用
开始办事
I am RealSubject, do action play
办完了
优缺点
优点
1)良好的扩展性。修改被代理角色并不影响调用者使用代理,对于调用者,被代理角色是透明的。
2)隔离,降低耦合度。代理角色协调调用者和被代理角色,被代理角色只需实现本身关心的业务,非自己本职的业务通过代理处理和隔离。
缺点
1)增加了代理类,实现需要经过代理,因此请求速度会变慢。