代理模式(一)之静态代理

前言

代理模式从定义上说就是给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用

一般情况下,我们可以通过继承或者聚合来实现代理,当然继承会造成类爆炸,而聚合则更灵活
不多说,模拟一个静态代理的情景
假设打野是一个接口,有gank方法,记录打野行为,打野具体对象盲僧,实现其gank的时间并记录下来,然后后续打野盲僧1、盲僧2分别记录打野具体对象的gank时间和gank日志(目前打野对象为LeeSin)

Jungle(打野接口)

1
2
3
4
public interface Jungle {
//打野gank方法
public void gank();
}

LeeSin(盲僧)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class LeeSin implements Jungle {
@Override
public void gank() {
//gank开始时间
long starts=System.currentTimeMillis();
System.out.println("LeeSin is ganking...");
try {
//gank进行中
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//gank结束时间
long ends=System.currentTimeMillis();
System.out.println("gank time:"+(ends-starts));
}
}

接下来就是使用代理对象,比如用一个代理记录打野gank方法的时间
不妨先用继承(与后面聚合比较会发现继承将造成类爆炸)

1
2
3
4
5
6
7
8
9
10
11
12
//时间代理,记录gank时间
public class LeeSin1 extends LeeSin {
@Override
public void gank() {
long starts=System.currentTimeMillis();
super.gank();
long ends=System.currentTimeMillis();
System.out.println("gank time:"+(ends-starts));
}
}

如果这时再有一个log代理,记录gank日志

1
2
3
4
5
6
7
8
9
10
public class LeeSin2 extends LeeSin {
@Override
public void gank() {
System.out.println("LeeSin starts ganking");
super.gank();
System.out.println("LeeSin ends ganking");
}
}

如果这时说先记录日志在记录时间或者先记录时间在记录日志,这时就要写两个类
列出主体代码(另一个调换位置)

1
2
3
4
5
6
7
8
9
10
11
@Override
public void gank() {
System.out.println("LeeSin starts ganking");
long starts=System.currentTimeMillis();
super.gank();
long ends=System.currentTimeMillis();
System.out.println("gank time:"+(ends-starts));
System.out.println("LeeSin ends ganking");
}

可能目前代理类较少,还没有缺陷,如果是100个甚至更多,只要稍微要求下顺序或者其他,就要增加一个类,显然造成类爆炸,所以继承代理不可取

利用聚合代理(因为被代理类都是继承或者实现Jungle,所以可以用jungle代理,知识子类行为不同而已
打野时间代理类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class LeeSinTimeProxy implements Jungle {
//代理对象
Jungle leesin;
public LeeSinTimeProxy(Jungle leesin) {
super();
this.leesin = leesin;
}
@Override
public void gank() {
long starts=System.currentTimeMillis();
leesin.gank();
long ends=System.currentTimeMillis();
System.out.println("gank time:"+(ends-starts));
}
}

日志代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class LeeSinlogProxy implements Jungle {
Jungle leesin;
public LeeSinlogProxy(Jungle leesin) {
super();
this.leesin = leesin;
}
@Override
public void gank() {
System.out.println("LeeSin starts ganking");
leesin.gank();
System.out.println("LeeSin ends ganking");
}
}

测试类

1
2
3
4
5
6
7
8
public static void main(String[] args) {
LeeSin leesin=new LeeSin();
Jungle jungletime=new LeeSinTimeProxy(leesin);
Jungle junglelog=new LeeSinlogProxy(jungletime);
junglelog.gank();
}

测试结果:

LeeSin starts ganking
LeeSin is ganking…
gank time:1005
gank time:1005
LeeSin ends ganking

注意这里是日志代理时间,时间代理盲僧,如果更改顺序,只需改变被代理对象即可
Alt text

至此我们可以简单归纳一下静态代理
大概有抽象角色:如打野 ,代理角色(被聚合类的引用),以及真实角色

最后不得不提的是静态代理虽然简单,但是有很多局限性,比如它是在编译期由我们主动创建的,也就说在程序运行前已经存在在.class文件中了,如果代理类一旦多的话,代理内容就无法复用,新增方法时,代理对象也要跟着增加方法。

所以代理设计模式真正的魅力和强大之处而是动态代理!!

热评文章