设计模式--代理模式

定义

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

代理模式是指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象。
为什么要采用这种间接的形式来调用对象呢?一般是因为客户端不想直接访问实际的对象,或者访问实际的对象存在困难,因此通过一个代理对象来完成间接的访问。

静态代理模式

代理模式中的角色:

  1. 抽象主题角色(Subject):声明了目标对象和代理对象的共同接口,这样一来任何可以使用目标对象的地方都能用代理对象。
  2. 具体主题角色(RealSubject):称为委托角色或被代理角色。实现了目标对象。
  3. 代理主题角色(Proxy):也叫委托类、代理类。代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象。代理对象提供一个与目标对象相同的接口,以便可以在任何时候代替目标对象。

Subject

1
2
3
interface MySubject{
public void operate();
}

RealSubject

1
2
3
4
5
6
class RealSubject implements MySubject{
@Override
public void operate(){
System.out.println("RealSubject");
}
}

Proxy

1
2
3
4
5
6
7
8
9
10
11
12
13
class Proxy implements MySubject{
private MySubject mySubject;
@Override
public void operate(){
if(mySubject == null){
mySubject = new RealSubject();
}
System.out.println("0707, this is Proxy: ");
this.mySubject.operate();
System.out.println("over");
}
}

来自客户端的调用

1
2
3
4
5
6
public class ProxyPattern {
public static void main(String[] args){
MySubject mySubject = new Proxy();
mySubject.operate();
}
}

输出结果

1
2
3
0707, this is Proxy:
RealSubject
over

从上面的例子可以看出来,代理对象将客户端的调用派给目标对象,在调用目标对象的方法之前和之后都可以执行特定操作。

动态代理模式

在实现动态代理模式之前,首先了解一下以下内容:

Jdk通过java.lang.reflect.Proxy包来支持动态代理,在Java中要创建一个代理对象,必须调用Proxy类的静态方法newProxyInstance,该方法的原型如下:

1
Object Proxy.newProxyInstance(ClassLoader loader, Class<?> []interfaces, InvocationHandler handler) throws Exception;

loader:类加载器,使用null使用默认的加载器
interfaces:接口或对象的数组,代理对象和真实对象共有的接口
handler:调用处理器,必须是实现了InvocationHandler接口的对象,其作用是定义代理对象中需要执行的具体操作。

InvocationHandler接口中只有一个方法invoke,它的作用就跟Runnable中的run方法类似,定义了代理对象在执行真实对象的方法时所希望执行的动作。其原型如下:

1
Object invoke(Object proxy, Method method, Object[] objs) throws Throwable;

proxy:表示执行这个方法的代理对象
method:表示真实对象实际需要执行的方法
args:表示真实对象实际执行方法时所需的参数

Subject

1
2
3
4
5
interface MySubject{
String CatSounds();
String DogSounds();
String SnakeSounds();
}

RealSubject1 && RealSubject2 ……

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class RealSubject1 implements MySubject{
@Override
public String CatSounds(){
return "miaomiaomiao~~~~";
}
@Override
public String DogSounds(){
return "wangwangwang~~~~";
}
@Override
public String SnakeSounds(){
return "sisisi~~~";
}
}
class RealSubject2 implements MySubject{
@Override
public String CatSounds(){
return "niaoniaoniao~~~";
}
@Override
public String DogSounds(){
return "aoaoao~~~~";
}
@Override
public String SnakeSounds(){
return "ssssss~~~~";
}
}

Proxy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class ProxyHandler implements InvocationHandler {
private Object object;
public Object newProxyInstance(Object realObj){
this.object = realObj;
Class<?> classType = this.object.getClass();
return Proxy.newProxyInstance(classType.getClassLoader(), classType.getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
System.out.println("0707, this is AnimalProxy");
Object object = method.invoke(this.object, args);
System.out.println(object);
return object;
}
}

来自客户端的调用

1
2
3
4
5
6
7
8
9
public class ProxyPattern {
public static void main(String[] args){
MySubject mySubject1 = (MySubject) new ProxyHandler().newProxyInstance(new RealSubject1());
mySubject1.CatSounds();
MySubject mySubject2 = (MySubject) new ProxyHandler().newProxyInstance(new RealSubject2());
mySubject2.DogSounds();
}
}

动态代理模式通过使用反射,可以在运行期决定加载哪个类,避免了一个类对应一个代理的问题;同时,通过统一的invoke方法,统一了代理类对原函数的处理过程,使用动态代理很大程度上减少了重复的代码,降低了维护的复杂性和成本。