代理模式

代理模式也叫委托模式,许多其他的模式如状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了代理模式。
在日常应用中,代理模式可以提供非常好的访问控制。

定义

为其他对象提供一种代理以控制这个对象的访问。

比如,我们的DB的访问权限不能直接公开,一般会公开一个接口来提供对这些数据。

代理模式通用类图

实现

抽象主题Subject

可以是抽象类或者接口,普通的业务类型定义。

1
2
3
public interface Subject{
public void request();
}

具体主题RealSubject

委托角色或者被代理角色。业务逻辑的具体执行者。

1
2
3
4
5
public class RealSubject implements Subject{
public void request(){
//do something.
}
}

代理主题Proxy

代理类、委托类, 负责对真实角色的调用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后处理工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Proxy implements Subject{
private Subject subject = null;

public Proxy(){
this.subject = new Proxy();
}

public Proxy(Subject subject){
this.subject = subject;
}

public void request(){
this.before();
this.subject.request();
this.after();
}

private void before(){
//before
}
private void after(){
//after.
}
}

应用

优点

  • 职责清晰
    真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事物,通过后期的代理完成一件事物,附带的结果就是编程简洁清晰。
  • 扩展性好
    具体主题角色是随时都会发生变化的,只要它实现了接口,代理类可以在不做任何修改的情况下使用。
  • 智能化
    用于动态代理。

扩展

普通代理

客户端只能访问代理角色,而不能访问真实角色。屏蔽了真实角色的变更对高层模块的影响。该模式适合对扩展性要求较高的场合。一般通过编程规范类约束来禁止new一个真实的角色。

这种方式调用者只需要知道代理即可, 不需要知道代理了谁。

普通代理的实现者:

1
2
3
4
5
6
7
8
9
10
11
12
public class GamePlayer implements IGamePlayer{
private String name = "";
public GamePlayer(IGamePlayer _gamePlayer, String _name)throws Exception{
if(_gamePlayer == null || !(_gamePlayer instanceof GameProxy)){
throw new Exception("Create Not Allowed!");
}
this.name = _name;
}
public void killMonster(){
//do...
}
}

普通代理的代理者:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class GamePlayerProxy implements IGamePlayer{
private IGamePlayer gamePlayer = null;
public GamePlayerProxy(String name){
try{
gamePlayer = new GamePlayer(this,name);
}catch(Exception e){
//TODO
}
}

public void killMonster(){
this.gamePlayer.killMonster();
}
}

强制代理

只有通过真实角色指定的代理类才可以访问。

1
2
3
4
public interface IGamePlayer{
void killMonster();
public IGamePlayer getProxy();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class GamePlayer implements IGamePlayer{
private String name = "";
private IGamePlayer proxy = null;
public GamePlayer(String _name){
this.name = _name;
this.proxy = new GamepPlayerProxy(this);
}
public IGamePlayer getProxy(){
return this.proxy;
}
public void killMonster(){
//do...
}
}
1
2
3
4
5
6
7
8
9
public class GamePlayerProxy implements IGamePlayer{
private IGamePlayer gamePlayer = null;
public GamePlayerProxy(IGamePlayer _gamePlayer){
this.gamePlayer = _gamePlayer;
}
public void killMonster(){
this.gamePlayer.killMonster();
}
}

动态代理

在实现阶段不需要关心代理谁, 在运行阶段才指定代理哪个对象。

通过InvocationHandler接口,所有方法都由该Handler来接管实际的业务处理。

在不改变已有代码结构的情况下增强或者控制对象的行为。

动态代理Handler类:

1
2
3
4
5
6
7
8
9
public class MyInvocationHandler implements InvocationHandler{
private Object target = null;
public MyInvocationHandler(Object _obj){
this.target = _obj;
}
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable{
return method.invoke(this.target, args);
}
}

通知接口与实现

1
2
3
4
5
6
7
8
public interface IAdvice{
public void exec();
}
public class BeforeAdvice implements IAdvice{
public void exec(){
//....
}
}

动态代理类:

1
2
3
4
5
6
7
8
public class DynamicProxy<T>{
public static <T> T newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h){
if(condition){ //在condition连接点执行BeforeAdvice通知。
(new BeforeAdvice()).exec();
}
return (T)Proxy.newProxyInstance(loader, interface, h);
}
}

Client:

1
2
3
4
Subject subject = new RealSubject();
InvocationHandler handler = new MyInvocationHandler(subject);
Subject proxy = DynamicProxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), handler);
proxy.killMonster();

扩展

  • CGLib
1
2
3
4
5
6
7
8
9
10
public class LogInterceptor implements MethodInterceptor {

public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

System.out.println("Before Interceptor1");
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("After Interceptor1");
return result;
}
}
1
2
3
4
5
6
7
8
9
10
public class LogInterceptor2 implements MethodInterceptor {

public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

System.out.println("Before Interceptor2");
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("After Interceptor2");
return result;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
public class LogCallBackFilter implements CallbackFilter {

public int accept(Method method) {
if ("upgrade".equals(method.getName())){
System.out.println("Upgrade Filter");
return 0;
}

System.out.println("Kill Monster Filter");
return 1;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
LogInterceptor logInterceptor = new LogInterceptor();

LogInterceptor2 logInterceptor2 = new LogInterceptor2();

Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(GamePlayer.class);
enhancer.setCallbacks(new Callback[]{logInterceptor,logInterceptor2, NoOp.INSTANCE});

enhancer.setCallbackFilter(new LogCallBackFilter());

IGamePlayer gamePlayer = (IGamePlayer)enhancer.create(new Class[]{String.class}, new Object[]{"Lisi"});

gamePlayer.killMonster();
gamePlayer.upgrade();
  • ASM
  • AOP

扩展阅读
cglib动态代理、asm学习笔记
Java动态代理详解