白话-23种设计模式6-代理模式
一、白话
代理模式,指定第三方作为代表。我只负责和我的代表沟通,其他人只能和代理通过,然后代理进行判断是否需要转述给我或者自己处理掉即可。现实举例就像打官司,我们需要请律师来代理我们,我们赋予律师谈判的权利,对方有什么要求也只能跟我律师谈,律师再和我沟通。现实还有很多例子。淘宝店家给工厂代理,代理工厂给品牌方代理加工,火车代售点给火车站代理,自动聊天回复等等。
二、定义
代理模式(英语:Proxy Pattern)是程序设计中的一种设计模式。所谓的代理者是指一个类别可以作为其它东西的接口。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
- 抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
- 真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
- 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。
三、静态代理
静态代理:在程序运行之前,代理类的.class文件就已经生成。
/**
* 抽象角色-提供共有接口
*/
public interface IPerson {
// 谈判
public String negotiations(String msg);
}
/**
* 真实角色-我
*/
public class Me implements IPerson {
@Override
public String negotiations(String msg) {
System.out.println("谈判结束");
return "谈判结束";
}
}
/**
* 代理角色-代替我执行权限
*/
public class Lawyers implements IPerson {
private IPerson person = new Me(); // 具有真实的角色,赋予权限
@Override
public String negotiations(String msg) {
if ("谈判".equals(msg)) {
return "谈判中。。。";
} else if ("接受要求".equals(msg)) {
System.out.println("中间方:双方互谈");
return person.negotiations(msg);
} else {
return "不同意,继续谈判";
}
}
}
public class ProxyApplication {
// 客户端调用
public static void main(String[] args) {
IPerson person = new Lawyers(); // 代理角色
String result = person.negotiations("接受要求");
System.out.println("谈判结果 = " + result);
}
}
输出结果:
Me和Lawyers的代理关系已确定,查看字节码文件也是存在.class,此时Lawyers只能代理Me。
四、动态代理
JDK动态代理
JDK动态代理,基于接口实现代理,jdk自带的代理方案,基于反射的机制生成代理对象。方案:需要实现InvocationHandler,通过Proxy生成代理对象。需要注意的是基于接口进行代理,否则会出现转换错误。
/**
* jdk动态代理,实现InvocationHandler接口
*/
public class JdkProxy implements InvocationHandler {
private Object target; // 需要代理的目标对象
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK代理开始");
Object result = method.invoke(target, args);
System.out.println("JDK代理结束");
return result;
}
// 注入真实对象,生成返回代理对象
public Object getJDKProxy(Object targetObject) {
// 为目标对象target赋值
this.target = targetObject;
// JDK动态代理,生成代理对象
Object newProxyInstance = Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
return newProxyInstance;
}
public static void main(String[] args) {
JdkProxy jdkProxy = new JdkProxy(); // 实例化JDK动态代理对象
// Me me = (Me) jdkProxy.getJDKProxy(new Me()); // 获取代理对象
// JDK需要基于接口进行代理,如果直接使用类,会出现转换错误
// Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to com.example.proxy.model.Me
// at com.example.proxy.model2.JdkProxy.main(JdkProxy.java:37)
IPerson me = (IPerson) jdkProxy.getJDKProxy(new Me()); // 获取代理对象
me.negotiations("同意接受");// 调用谈判方法
}
}
Cglib动态代理
cglib是针对类实现代理,需要额外的依赖包asm和cglib,使用asm字节码框架实现。方案:实现MethodIntercepter接口,通过Enhancer生成真实对象的子类。需要注意,本质是基于生成类的子对象实现,所以不要把类定义成final,否则无用调用。
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>5.0.3</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.1</version>
</dependency>
/**
* cglib动态代理, 需要单独的依赖,需要实现MethodInterceptor接口
*/
public class CglibProxy implements MethodInterceptor {
private Object target;
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib 动态代理,代理开始");
Object result = method.invoke(target, objects);
System.out.println("cglib 动态代理,代理结束");
return result;
}
public Object getCglibProxy(Object targetObject) {
this.target = targetObject; // 目标对象赋值
Enhancer enhancer = new Enhancer();
// 设置附列,Cglib是针对指定的类生成一个子类
enhancer.setSuperclass(targetObject.getClass());
enhancer.setCallback(this);
Object result = enhancer.create();// 创建并返回代理对象
return result;
}
public static void main(String[] args) {
CglibProxy cglibProxy = new CglibProxy(); // 实例化CglibProxy对象
Me meProxy = (Me) cglibProxy.getCglibProxy(new Me()); // 获取代理对象
meProxy.negotiations("接受请求"); // 代理方法调用
}
}
五、总结
优点:一定程度上降低了系统的耦合度。代理模式能将代理对象和真实被调用的目标对象分离。对目标对象的功能增强。有保护对象的作用。
- 点赞
- 收藏
- 关注作者
评论(0)