java设计模式中代理模式的知识点
- 更新时间:2020-06-18 09:33:25
- 编辑:刘靖柏
代理模式是java最常见的设计模式之一。spring的aop就是使用了代理模式。
一般而言,代理模式分为静态代理和动态代理两种。
作为结构类的设计模式,作用在于不修改类内部代码的情况下,对类进行拓展,是对继承机制的一种补充。
eg :下面就用户登录这个例子实现一下代理模式。
基本需求是:实现用户的登录和修改昵称功能。
上代码,先是IUser接口和user实现类
public interface IUser { //登录 void login(String userId,String password); //修改昵称 void editNickname(String nickname); }
public class User implements IUser { private String nickname; private String userId; private String password; public User(String userId,String password){ this.userId = userId; this.password = password; } @Override public void login(String userId, String password){ if(this.userId == userId && this.password == password){ System.out.println("用户登录成功"); } else System.out.println("用户登录失败"); } @Override public void editNickname(String nickname) { this.nickname = nickname; System.out.println("修改昵称成功,当前用户的昵称是:"+this.nickname); } }
客户端类
public class Client { public static void main(String[] args) { //不调用代理模式时 IUser user = new User("firs","123"); user.login("firs", "123"); user.editNickname("大风"); }
还是非常简单的。可是后面产品经理跟你说,我们需要增加一个记录用户行为的功能,这下该怎么办呢?直接修改user类?不不不,用代理模式。
增加一个代理类,在代理类里面写“记录用户行为”的功能就好,不修改类,只拓展类,减少错误发生。
import java.util.Date; import java.util.HashMap; import java.util.Map; /** * 静态代理类必须实现接口,而且需要新创建一个类的代码出来 * @author Administrator * */ public class StaticProxy implements IUser { private IUser user; public StaticProxy(String userId,String password){ this.user = new User(userId,password); } //登陆前的操作,记录当前登录的时间 void noteLoginInfo(String[] params, String opreate){ Map<String,Object> loginInfo = new HashMap<>(); loginInfo.put("params", params); loginInfo.put("opreate", opreate); loginInfo.put("opreateTime", new Date()); System.out.println("记录用户操作成功"); } @Override public void login(String userId, String password){ noteLoginInfo(new String[]{userId, password},"login"); user.login(userId, password); } @Override public void editNickname(String nickname) { noteLoginInfo(new String[]{nickname},"editNickname"); user.editNickname(nickname); } }
客户端类:
public class Client { public static void main(String[] args) { //不调用代理模式时 IUser user = new User("firs","123"); user.login("firs", "123"); user.editNickname("大风"); System.out.println(""); System.out.println("=============调用静态代理模式后==========="); //需要实现记录用户登录和修改昵称操作的日志功能 //基于“拓展开发,修改关闭”的设计准则,我们可以用静态代理的方式 IUser proxy = new StaticProxy("firs","123"); proxy.login("firs", "123"); proxy.editNickname("我还是大风"); }
这样子只需要修改客户端类和增加静态代理就可以了,完美实现。可是需求是无穷无尽的,产品经理跟你说:“我们增加了一个管理员角色,还有二级管理员”啥啥啥的一大堆角色,
这就尴尬了,每个角色都要建一个静态代理类,类爆炸了吧。不急,我们有动态代理模式。
动态代理模式在于不用自己新建代理类,你传具体的实现类(主体)给他,他就默认给你生成了一个代理类。
从本质上来说,它是利用了java的反射机制在运行时动态地生成了相应的代理类。
没有反射,就没有动态代理。
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.Date; import java.util.HashMap; import java.util.Map; /** * 动态代理类不用和主体类继承同一个接口 * @author Administrator * */ public class DynamicProxy implements InvocationHandler { private Object object; public DynamicProxy(String userId,String password,Class<?> c){ Object obj = null; try { obj = Class.forName(c.getName()) .getConstructor(String.class,String.class) .newInstance(userId,password); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } this.object = obj; } //登陆前的操作,记录当前登录的时间 void noteLoginInfo(String[] params, String opreate){ Map<String,Object> loginInfo = new HashMap<>(); loginInfo.put("params", params); loginInfo.put("opreate", opreate); loginInfo.put("opreateTime", new Date()); System.out.println("记录用户操作成功"); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String[] params = new String[args.length]; for(int i = 0 ;i < args.length ; i++){ params[i] = args[i].toString(); } noteLoginInfo(params, method.getName()); return method.invoke(object, args); } }
最后的客户端类:
package com.test.my; import java.lang.reflect.Proxy; public class Client { public static void main(String[] args) { //不调用代理模式时 IUser user = new User("firs","123"); user.login("firs", "123"); user.editNickname("大风"); System.out.println(""); System.out.println("=============调用静态代理模式后==========="); //需要实现记录用户登录和修改昵称操作的日志功能 //基于“拓展开发,修改关闭”的设计准则,我们可以用静态代理的方式 IUser proxy = new StaticProxy("firs","123"); proxy.login("firs", "123"); proxy.editNickname("我还是大风"); System.out.println(""); System.out.println("=============调用动态代理模式后==========="); DynamicProxy dynamicProxy = new DynamicProxy("firs","123",Admin.class); ClassLoader cl = Admin.class.getClassLoader(); IUser iuser = (IUser)Proxy.newProxyInstance(cl, new Class[]{IUser.class}, dynamicProxy); iuser.login("firs","123"); iuser.editNickname("使用动态代理后的大风"); } }
因为需求而增加的Admin类
public class Admin implements IUser { private String nickname; private String userId; private String password; public Admin(String userId,String password){ this.userId = userId; this.password = password; } @Override public void login(String userId, String password){ if(this.userId == userId && this.password == password){ System.out.println("用户登录成功"); } else System.out.println("用户登录失败"); } @Override public void editNickname(String nickname) { this.nickname = nickname; System.out.println("修改昵称成功,当前用户的昵称是:"+this.nickname); } }
总结:
1.静态代理模式相对来说比较简单,要点在于对于每个实现类(subject主体)新建一个代理类,该代理类内有实体类(subject主体)的引用,从而可以实现对原有实现类(subject主体)的控制,包括aop的控制等。
2.静态代理是有局限性的,对于每个实体类可能都需要新建一个静态代理类,这样子可能会造成静态代理类过多的情况,所以动态代理应运而生了。
3.动态代理不局限于具体的实现类(subject主体),在其内部是用object存取实体类的引用,再利用反射获得该实体类的各种方法,从而实现对实现类(subject主体)的面向 切面AOP编程控制。
4.上述的写法是JDK里的动态代理,不是特别完美,因为这种动态代理需要实体类实现至少一个接口。问题是并不是所有的类都会有接口,所以说不完美在这里。
上面都是我自己对于代理模式的理解,如有错漏,还请批评指正,多谢。
以上这篇java设计模式-代理模式(实例讲解)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持码农之家。
相关教程
-
详解Java策略模式定义与用法
这篇文章主要介绍了Java设计模式之策略模式定义与用法,结合具体实例形式详细分析了Java策略模式的概念、原理、定义及相关操作技巧,需要的朋友可以参考下
发布时间:2020-03-19
-
java装饰者模式23种设计模式总结
这篇文章主要为大家详细介绍了23种设计模式之java装饰者模式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
发布时间:2020-01-23
-
javascript设计模式之对象工厂函数与构造函数实例详解
这篇文章主要介绍了javascript设计模式之对象工厂函数与构造函数详解,使用对象字面量,或者向空对象中动态地添加新成员,是最简单易用的对象创建方法,除了这两种常用的对象创建方式,
发布时间:2020-01-28
-
Java设计模式之原型模式Prototype
这篇文章主要为大家详细介绍了Java设计模式之Prototype原型模式的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
发布时间:2020-01-27
-
Java 观察者模式学习
这篇文章主要为大家详细介绍了Java学习笔记之观察者模式的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
发布时间:2020-03-02
-
Java设计中Builder模式实例详解
这篇文章主要介绍了从一个Person例子进行分析重叠构造器模式、Builder模式的使用场景以及运用JavaBeans模式弥补重叠构造器模式的不足
发布时间:2019-11-22
-
JavaScript命令模式实例讲解
这篇文章主要介绍了JavaScript设计模式之命令模式,结合实例形式分析了javascript命令模式的概念、原理、用法及相关注意事项,需要的朋友可以参考下
发布时间:2020-01-25
-
java单例模式知识点深入了解
这篇文章主要介绍了你真的了解java单例模式了吗?实际上单例模式有着好几个变种,并且多线程中涉及到线程安全问题,,需要的朋友可以参考下
发布时间:2019-07-03
-
实例分析JavaScript设计模式之策略模式
这篇文章主要为大家详细介绍了JavaScript设计模式之策略模式的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
发布时间:2020-02-22
-
java备忘录模式
这篇文章主要为大家详细介绍了23种设计模式之java备忘录模式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
发布时间:2020-02-10
-
第三方JavaScript编程
第三方JavaScript应用程序是自包含的应用组件,通常都是小脚本或插件,能够为Web站点增加功能。它们往往是由独立的组织或个人提供的,代码和文件都是来自于远程的Web地址。 《第三方JavaS
大小:74.2 MBJavaScript电子书
-
Java遗传算法编程
本书简单、直接地介绍了遗传算法,并且针对所讨论的示例问题,给出了Java代码的算法实现。全书共分为6章。本书适合机器学习爱好者阅读,尤其适合对遗传算法的理论和实现感兴趣的读者阅
大小:28.8 MBJava算法电子书
-
JavaScript函数式编程
JavaScript 是近年来非常受瞩目的一门编程语言,它既支持面向对象编程,也支持函数式编程。本书专门介绍JavaScript函数式编程的特性。
大小:42158 MB MJavaScript
-
Java游戏编程开发教程
Java游戏编程开发教程 是一本面向广大编程爱好者的游戏设计类图书。本书从最基本的Java图形开发开始,对游戏的原理及其Java程序实现进行了详细介绍,包括动画的实现、音效的处理、鼠标和
大小:160.3 MBJava编程电子书
-
Spark 2.2.x API 中文参考文档+Spark java developers
Spark 2.2.x Doc API 中文参考文档, 本教程是对使用 Spark 的一个简单介绍。首先我们会通过 Spark 的交互式 shell 简单介绍一下 (Python 或 Scala) API,然后展示如何使用 Java、Scala 以及 Python 编写一个 Spark 应用程序。 Spark Shell 提供了一种简单的方式来学习 Spark API,同时它也是一个强大的交互式数据分析工具。Spark Shell 既支持 Scala(Scala 运行在 Java 虚拟机上,所以可以很方便
大小:7.82 MBSpark
-
Java Web应用程序开发
《企业级卓越人才培养(信息类专业集群)解决方案十三五规划教材:Javaweb应用程序开发》通过对JAVAweb相关知识的介绍,学习IO流、JDBC、Web服务器、JSP页面以及对JSP内置对象等内容,每个知识点后
大小:5.3 MBJava Web开发电子书