结构型设计模式:代理模式
时间:2022-07-23
本文章向大家介绍结构型设计模式:代理模式,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
代理模式主要作用是不改变原始类的情况下,通过代理类来访问原始类方法,从而对原始类方法进行增强。当然,把增强功能直接放入原始类也是可以的,但是这样不符合开闭原则,而且容易把业务代码和非业务代码耦合。代理模式的实现有2种方式
1.代理类和原始类实现同一个接口,代码如下:
public interface UserManager {
//新增用户抽象方法
void addUser(String userName, String password);
//删除用户抽象方法
void delUser(String userName);
}
public class UserManagerImpl implements UserManager{
@Override
public void addUser(String userName, String password) {
System.out.println("传入参数为 userName: "+userName+" password: "+password);
}
@Override
public void delUser(String userName) {
System.out.println("传入参数为 userName: "+userName);
}
}
public class UserManagerProxy implements UserManager{
private UserManager userManager = new UserManagerImpl();
@Override
public void addUser(String userName, String password) {
System.out.println("proxy addUser");
userManager.addUser("zhangsan", "123456");
}
@Override
public void delUser(String userName) {
System.out.println("proxy deleteUser");
userManager.delUser("zhangsan");
}
}
先定义了一个UserManager接口, UserManagerImpl实现了这个接口,做具体的操作。同时,UserManagerProxy也实现了这个接口,但是UserManagerProxy自己不做具体的业务,而是组合了UserManagerImpl,用UserManagerImpl来做业务操作。UserManagerProxy自身做一些增强操作,比如记录日志等。
2.如果原始类没有实现接口,这种情况下代理模式就得用继承的方式来实现了。如下代码:
public class UserManagerProxy1 extends UserManagerImpl{
@Override
public void addUser(String userName, String password) {
System.out.println("proxy addUser");
super.addUser("zhangsan", "123456");
}
@Override
public void delUser(String userName) {
System.out.println("proxy deleteUser");
super.delUser("zhangsan");
}
}
上面的都是静态代理,静态代理的问题是针对每一个被代理类都需要生成一个代理类,而且代理类里面需要重新实现被代理类的那一套代码逻辑。使用动态代理可以解决这个问题,下面我们看一下动态代理的实现。
3.jdk中的动态代理
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;
}
//定义获取代理对象方法
private Object getJDKProxy(Object targetObject){
//为目标对象target赋值
this.target = targetObject;
//JDK动态代理只能针对实现了接口的类进行代理,newProxyInstance 函数所需参数就可看出
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
}
public static void main(String[] args) {
JdkProxy jdkProxy = new JdkProxy();//实例化JDKProxy对象
UserManager user = (UserManager) jdkProxy.getJDKProxy(new UserManagerImpl());//获取代理对象
user.addUser("admin", "123123");//执行新增方法
}
}
jdk只能对实现了接口的类做代理,下面看一下cglib代理
4.cglib代理
cglib代理是基于代理类生成了一个子类,就像上面2的实现一样,代码如下:
public class CglibProxy implements MethodInterceptor {
private Object target;//需要代理的目标对象
//重写拦截方法
@Override
public Object intercept(Object obj, Method method, Object[] arr, MethodProxy proxy) throws Throwable {
System.out.println("Cglib动态代理,监听开始!");
Object invoke = method.invoke(target, arr);//方法执行,参数:target 目标对象 arr参数数组
System.out.println("Cglib动态代理,监听结束!");
return invoke;
}
//定义获取代理对象方法
public Object getCglibProxy(Object objectTarget){
//为目标对象target赋值
this.target = objectTarget;
Enhancer enhancer = new Enhancer();
//设置父类,因为Cglib是针对指定的类生成一个子类,所以需要指定父类
enhancer.setSuperclass(objectTarget.getClass());
enhancer.setCallback(this);// 设置回调
Object result = enhancer.create();//创建并返回代理对象
return result;
}
public static void main(String[] args) {
CglibProxy cglib = new CglibProxy();//实例化CglibProxy对象
UserManager user = (UserManager) cglib.getCglibProxy(new UserManagerImpl());//获取代理对象
user.delUser("admin");//执行删除方法
}
}
5.动态代理的使用
动态代理的使用场景非常广泛,在我们日常开发中,spring的事务管理就是用动态代理实现的。除此之外,比如对于缓存,我们可以在代理类中查询缓存,而在被代理类中查询数据库,代理类只有缓存中没有数据时,才会访问数据库。再比如RPC框架,我们可以通过代理类将缓存细节隐藏起来,只关注调用。
- Windows Server 2008R2配置MySQL Cluster
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(41)-组织架构
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(40)-精准在线人数统计实现-【过滤器+Cache】
- Enterprise Library深入解析与灵活应用(7):再谈PIAB与Unity之间的集成
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(39)-在线人数统计探讨
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(37)-文章发布系统④-百万级数据和千万级数据简单测试
- .Net 转战 Android 4.4 日常笔记(10)--PullToRefresh下拉刷新使用
- .Net 转战 Android 4.4 日常笔记(10)--ADT集成环境更新SDK
- Windows Server 2008R2 配置网络负载平衡(NLB)
- .Net 转战 Android 4.4 日常笔记(9)--常用组件的使用方法[附源码]
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(38)-Easyui-accordion+tree漂亮的菜单导航
- .Net 转战 Android 4.4 日常笔记(8)--常见事件响应及实现方式
- silverlight于javascript通信
- 微信上线小游戏:对流量基础入口应用商店革命
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 数据结构算法操作试题(C++/Python)——搜索插入位置
- 数据结构算法操作试题(C++/Python)——报数
- Java List.add()方法:向集合列表中添加对象
- Linux下查看NVIDIA的GPU使用情况
- 数据结构算法操作试题(C++/Python)——有效的数独
- Java List.addAll()方法:添加所有元素到列表中
- HDFS的Shell操作(开发重点)
- 数据结构算法操作试题(C++/Python)——字符串相乘
- Java基础知识笔记四(详细)
- [推荐]Linux入门系列(三)Vim编辑器(Vim工作模式+代码演示)
- 机器学习性能评价指标汇总
- [推荐]Linux入门系列(四)系统用户账号管理(代码图文示例)
- 逆波兰表达式
- 字符串:替换空格
- 字符串:花式反转还不够!