设计模式--静态代理模式和动态代理模式原理及实现
代理模式(委托模式)
为其他对象提供一种代理以控制对这个对象的访问。引入代理对象来间接访问目标对象
代理模式优点:
- 职责清晰:真实的角色就是实现实际的业务逻辑,不需关心其他非本职责的事务
- 高扩展性:代理类可以在不做任何修改的情况下继续使用
- 智能化:动态代理演示
代理模式缺点:
- 在客户端和真实对象之间添加了代理,会造成请求的处理速度变慢
- 实现代理模式比较复杂,需要额外的工作
代理模式的扩展:
普通代理
客户端只能访问代理角色,而不能直接访问真实角色。
1
2
3
4
5
6
7
8
9public class Client {
public static void main(String[] args){
//屏蔽了GamePlayer的真实角色访问
GamePlayerProxy gamePlayerProxy = new GamePlayerProxy("wxy");
gamePlayerProxy.login("wxy","124");
gamePlayerProxy.killBoss();
gamePlayerProxy.upgrade();
}
}Client只是调用了
GamePlayerProxy
代理角色,而不知道真实角色是谁。非常适合扩展性要求较高的场景。强制代理
通过真实角色来找到代理角色,否则不能访问。由真实角色来管理代理角色。不允许直接访问真实角色
1
2
3
4
5
6
7
8
9
10
11public class Client {
public static void main(String[] args){
//必须是真实角色的代理对象才可以使用
IGamePlayer gamePlayerProxy = new GamePlayer("wxy").getProxy();
//直接生成代理对象无效
//GamePlayerProxy gamePlayerProxy = new GamePlayerProxy(new GamePlayer("wzr5"));
gamePlayerProxy.login("wxy","124");
gamePlayerProxy.killBoss();
gamePlayerProxy.upgrade();
}
}代理是有个性的
一个类可以实现多个接口,完成不同任务的整合。代理类不仅可以实现主题接口,也可以实现其他接口完成不同的任务。
动态代理
不需要显式实现与目标对象类相同的接口,将这种实现推迟到程序运行时由JVM实现。
原理:通过Java反射机制的
method.invoke()
调用动态代理类对象方法,从而自动调用目标对象的方法。优点:1. 只需要一个代理类就可以解决创建多个静态代理的问题,避免重复代码。2. 更加灵活
缺点:1. 效率低
需要通过反射机制,间接调用目标对象方法
2.应用场景局限只能针对接口创建代理类,即只能动态代理实现了接口的类
应用场景:
需要代理对象数量较多的情况下使用
AOP
-面向切面编程可以通过预编译的方式在运行期动态代理实现程序功能的统一维护,有效降低业务之间的耦合度,提供程序的可用性并提高了开发的效率。开发中主要用在日志收集,性能分析等。
使用方法:
声明调用代理类
1
2
3
4
5
6
7
8
9
10
11
12
13
14public class GamePlayIH<T> implements InvocationHandler {
//被代理实例
T obj ;
public GamePlayIH(T _obj) {
this.obj = _obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(this.obj, args);
return result;
}
}声明目标对象类的抽象接口
1
2
3
4
5
6
7public interface IGamePlayer {
void login(String user, String pwd);
void killBoss();
void upgrade();
}声明目标对象类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public class GamePlayer implements IGamePlayer {
private String name = "";
public GamePlayer(String _name) {
this.name = _name;
}
@Override
public void login(String user, String pwd) {
System.err.println("登录名为:" + user + " 用户名为:" + this.name + "登录游戏");
}
@Override
public void killBoss() {
System.err.println(this.name + "打Boss");
}
@Override
public void upgrade() {
System.err.println(this.name + "升级了");
}
}通过动态代理对象,调用目标方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public class Client {
public static void main(String[] args) {
//创建目标对象
IGamePlayer player = new GamePlayer("wxy");
//创建调用处理对象
InvocationHandler handler = new GamePlayIH<>(player);
//指定产生代理对象的类加载器
ClassLoader cl = player.getClass().getClassLoader();
//创建动态代理对象
IGamePlayer gamePlayerProxy = (IGamePlayer) Proxy.newProxyInstance(cl, new Class[]{IGamePlayer.class}, handler);
//调用动态代理对象方法
gamePlayerProxy.login("wxy", "124");
gamePlayerProxy.killBoss();
gamePlayerProxy.upgrade();
}
}
Proxy
:提供用于创建动态代理类和实例的静态方法,并且还是创建出代理类的超类。
InvocationHandler
:调用处理器接口,自定义invoke()
,用于实现对真正委托类的代理方法。生成动态代理类实际调用的是invoke()
。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!