代理模式

代理模式(Proxy Pattern):给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问,它是一种对象结构型模式。

当无法或不想直接访问某个对象或访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象和代理对象需要实现相同的接口



  • Subject(抽象类):声明代理角色和真实角色共同的接口,可以是抽象类或接口
  • Proxy(代理类):持有真实对象的引用,通常,在代理类中,客户端在调用所引用的真实对象之前或之后还需要执行其他操作,不仅仅是调用真实对象中的操作
  • RealSubject(真实类):真实对象的业务操作

下面是代理模式的一个简单实现:

Subject 类:

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

RealSubject 类:

1
2
3
4
5
6
class RealSubject implements Subject {
@Override
public void request() {
LogUtils.i("我是真实对象");
}
}

Proxy 类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Proxy implements Subject {

private RealSubject mRealSubject;

public Proxy() {
mRealSubject = new RealSubject();
}

@Override
public void request() {
LogUtils.i("调用真实对象前");
mRealSubject.request();
LogUtils.i("调用真实对象后");
}
}

猛的一看和 装饰模式 非常的相似,装饰模式中的具体组件类(ConcreteComponent)和装饰类(Decorator)都实现同一个接口,代理模式中的抽象类(Subject)和代理类(Proxy)也是实现同一个接口,装饰类(Decorator)和代理类(Proxy)都是在真实对象的方法前面或者后面添加方法,但实际上,这两个模式还是又本质上的区别,装饰模式用于给一个对象动态添加方法,而代理模式用于控制一个对象的访问,隐藏对象的具体信息,代理模式中代理对象和真实对象间的关系在编译器就已经确定,而装饰模式是通过构造器传递,运行期才能确定,下面是 装饰类(Decorator) 的部分代码,对比 代理类(Proxy) 的代理就很清晰了

1
2
3
4
5
6
7
8
9
public class Decorator extends Component {

private Component component;

// 通过构造器传递对象
public Decorator(Component component) {
this.component = component;
}
}

看完代理模式和装饰模式的区别,再来了解一下代理模式中的动态代理,上面是静态代理的例子,代理对象在编译期就已经存在;而动态代理不同于静态代理,动态代理通过反射机制在运行期动态生成代理对象,Java 中提供了一个 InvocationHandler 接口实现动态代理,下面是示例代码:

DynamicProxy 类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class DynamicProxy implements InvocationHandler {

private Subject subject;

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

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
LogUtils.i("方法调用前");
Object invoke = method.invoke(subject, args);
LogUtils.i("方法调用后");
return invoke;
}
}

静态代理 Client 类:

1
2
Proxy proxy = new Proxy();
proxy.request();

动态代理 Client 类:

Java Subject realSubject = new RealSubject(); DynamicProxy dynamicProxy = new DynamicProxy(realSubject); Subject subject = (Subject)java.lang.reflect.Proxy.newProxyInstance(RealSubject.class.getClassLoader(), RealSubject.class.getInterfaces(),dynamicProxy); subject.request();

优点

  • 协调调用者和被调用者,一定程度上降低系统耦合
  • 客户端可针对抽象类进行编程,增加和替换代理类无须修改源代码,符合开闭原则,系统具有较好的灵活性和可扩展性

缺点

  • 客户端和真实对象之间增加了代理对象,有些类型的代理模式可能会造成请求的处理速度变慢,例如保护代理
  • 实现代理模式需要额外的工作量,有些代理模式实现过程较为复杂,例如远程代理

适用场景

  • 需要控制对一个对象的访问,为不同调用者提供不同级别的访问权限
  • 需要为一个对象提供一些额外的操作