这篇文章主要介绍了Java使用设计模式中的代理模式构建项目的实例展示,代理模式中的代理对象可以在客户端和目标对象之间起到中介的作用,需要的朋友可以参考下
概念
代理模式(Proxy):代理模式其实就是多一个代理类出来,替原对象进行一些操作。比如咱有的时候打官司需要请律师,因为律师在法律方面有专长,可以替咱进行操作表达咱的想法,这就是代理的意思。代理模式分为两类:1、静态代理(不使用jdk里面的方法);2、动态代理(使用jdk里面的InvocationHandler和Proxy)。
静态代理由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。
示例
这里我们举一个静态代理的例子:
类图:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
/**
* 游戏者接口
*
*/
public
interface
IGamePlayer {
// 登录游戏
public
void
login(String user, String password);
// 杀怪,网络游戏的主要特色
public
void
killBoss();
// 升级
public
void
upgrade();
}
|
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
|
/**
* 游戏者
*
*/
public
class
GamePlayer
implements
IGamePlayer {
private
String name =
""
;
// 通过构造函数传递名称
public
GamePlayer(String _name) {
this
.name = _name;
}
// 打怪,最期望的就是杀老怪
public
void
killBoss() {
System.out.println(
this
.name +
" 在打怪!"
);
}
// 进游戏之前你肯定要登录吧,这是一个必要条件
public
void
login(String user, String password) {
System.out.println(
"登录名为"
+ user +
" 的角色 "
+
this
.name +
"登录成功!"
);
}
// 升级,升级有很多方法,花钱买是一种,做任务也是一种
public
void
upgrade() {
System.out.println(
this
.name +
" 又升了一级!"
);
}
}
|
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
|
/**
* 客户端 对被代理对象不可见
*/
public
class
GamePlayerProxy
implements
IGamePlayer {
private
IGamePlayer gamePlayer =
null
;
//被代理对象
// 通过构造函数传递要对谁进行代练
public
GamePlayerProxy(String username) {
this
.gamePlayer =
new
GamePlayer(username);
}
// 代练杀怪
public
void
killBoss() {
this
.gamePlayer.killBoss();
}
// 代练登录
public
void
login(String user, String password) {
this
.gamePlayer.login(user, password);
}
// 代练升级
public
void
upgrade() {
this
.gamePlayer.upgrade();
}
}
|
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
|
/*
* 客户端 对被代理对象不可见
*/
public
class
GamePlayerProxy2
implements
IGamePlayer {
private
IGamePlayer gamePlayer =
null
;
//被代理对象
// 通过构造函数传递要对谁进行代练
public
GamePlayerProxy2(String username) {
this
.gamePlayer =
new
GamePlayer(username);
}
// 代练杀怪
public
void
killBoss() {
this
.gamePlayer.killBoss();
}
// 代练登录
public
void
login(String user, String password) {
System.out.println(
"登录时间是:"
+
new
Date().toLocaleString());
this
.gamePlayer.login(user, password);
}
// 代练升级
public
void
upgrade() {
this
.gamePlayer.upgrade();
System.out.println(
"升级时间是:"
+
new
Date().toLocaleString());
}
}
|
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
|
/*
* 客户端 对被代理对象不可见
*/
public
class
GamePlayerProxy3 {
private
IGamePlayer gamePlayer;
// 通过构造函数传递 被代练(代理)对象
public
GamePlayerProxy3(IGamePlayer gamePlayer) {
this
.gamePlayer = gamePlayer;
System.out.println(
"我是一名代练,我玩的角色是别人的,可以动态传递进来"
);
}
public
IGamePlayer getProxy() {
return
(IGamePlayer) Proxy.newProxyInstance(
this
.getClass().getClassLoader(),
new
Class[]{IGamePlayer.
class
},
new
MyInvocationHandler());
}
private
class
MyInvocationHandler
implements
InvocationHandler {
@Override
public
Object invoke(Object proxy, Method method, Object[] args)
throws
Throwable {
if
(method.getName().equals(
"login"
)) {
System.out.println(
"登录时间是:"
+
new
Date().toLocaleString());
}
if
(method.getName().equals(
"upgrade"
)) {
System.out.println(
"升级时间是:"
+
new
Date().toLocaleString());
}
method.invoke(gamePlayer, args);
return
null
;
}
}
}
|
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
34
35
36
37
38
39
40
41
|
public
class
Test {
public
static
void
main(String[] args) {
/*
* 普通的静态代理: 客户端不知道被代理对象,由代理对象完成其功能的调用
*/
IGamePlayer proxy = new GamePlayerProxy("X");
System.out.println("开始时间是:" + new Date().toLocaleString());
proxy.login("zhangSan", "abcd");
proxy.killBoss();
proxy.upgrade();
System.out.println("结束时间是:" + new Date().toLocaleString());
System.out.println();
/*
* 代理对象 增强了 被代理对象的功能
*/
IGamePlayer proxy2 = new GamePlayerProxy2("M");
proxy2.login("lisi", "efg");
proxy2.killBoss();
proxy2.upgrade();
System.out.println();
/*
* 动态代理:使用jdk提供的InvocationHandler,反射调用被代理对象的方法
* 结合java.reflect.Proxy 产生代理对象
* 动态传入被代理对象构造InvocationHandler,在handler中的invoke时可以增强被代理对象的方法的功能
* 或者说:(面向切面:)在什么地方(连接点), 执行什么行为(通知)
* GamePlayerProxy3中是方法名为login时通知开始时间,upgrade时通知结束时间
*/
GamePlayerProxy3 dynamic = new GamePlayerProxy3(new GamePlayer("Y"));
IGamePlayer dynamicPlayer = dynamic.getProxy();
dynamicPlayer.login("wangwu", "1234");
dynamicPlayer.killBoss();
dynamicPlayer.upgrade();
/*
* 面向切面: 一些相似的业务逻辑需要加在众多的地方,那们就可以把它提取到切面中, 切面也就是事务切面:如日志切面、权限切面、业务切面
*/
}
}
|
打印:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
开始时间是:2014-10-8 17:19:05
登录名为zhangSan 的角色 X登录成功!
X 在打怪!
X 又升了一级!
结束时间是:2014-10-8 17:19:05
登录时间是:2014-10-8 17:19:05
登录名为lisi 的角色 M登录成功!
M 在打怪!
M 又升了一级!
升级时间是:2014-10-8 17:19:05
我是一名代练,我玩的角色是别人的,可以动态传递进来
登录时间是:2014-10-8 17:19:05
登录名为wangwu 的角色 Y登录成功!
Y 在打怪!
升级时间是:2014-10-8 17:19:05
Y 又升了一级!
|
优点
(1)职责清晰
真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。
(2)代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了的作用和保护了目标对象的作用。
(3)高扩展性