java设计模式6——代理模式
程序员文章站
2022-03-10 16:15:34
java设计模式6——代理模式 1、代理模式介绍: 1.1、为什么要学习代理模式?因为这就是Spring Aop的底层!(SpringAop 和 SpringMvc) 1.2、代理模式的分类: 静态代理 动态代理 1.3、代理模式关系图(以租房子为例) 2、静态代理 2.1、角色分析: 抽象角色:一 ......
java设计模式6——代理模式
1、代理模式介绍:
1.1、为什么要学习代理模式?因为这就是spring aop的底层!(springaop 和 springmvc)
1.2、代理模式的分类:
- 静态代理
- 动态代理
1.3、代理模式关系图(以租房子为例)
2、静态代理
2.1、角色分析:
- 抽象角色:一般会使用接口或者抽象类来解决
- 真实角色:被代理的角色
- 代理客户:代理真实角色。代理真实角色后,我们一般会做一些附属的操作
- 客户:访问代理对象的人
2.2、例1(租房子演示)
2.2.1、抽象角色实现(房东抽象类)
package com.xgp.company.结构性模式.代理模式.静态代理.demo1; /** * 租房 */ public interface rent { void rent(); }
2.2.2、真实角色实现(房东的实现类)
package com.xgp.company.结构性模式.代理模式.静态代理.demo1; /** * 房东 */ public class host implements rent { @override public void rent() { system.out.println("房东要出租房子!"); } }
2.2.3、不通过代理进行租房
package com.xgp.company.结构性模式.代理模式.静态代理.demo1; public class client { public static void main(string[] args) { //直接找房东 host host = new host(); host.rent(); } }
运行结果:
房东要出租房子!
2.2.4、弊端
- 在实际的生活场景中,房东可能只卖房,而不负责租房
- 如果要提高租房子的成功率,必然还需要一些其他的服务,如:看房、谈价钱、签合同等,而这些房东并不想参与,因此产生了中介,也就是代理。
2.2.5、代理出现
package com.xgp.company.结构性模式.代理模式.静态代理.demo1; public class proxy implements rent { private host host; public proxy() { } public proxy(host host) { this.host = host; } @override public void rent() { seehouse(); host.rent(); fare(); hetong(); } //看房 public void seehouse() { system.out.println("中介代理看房"); } //收中介费 public void fare() { system.out.println("收中介费"); } public void hetong() { system.out.println("签合同"); } }
2.2.6、通过代理来租房子
package com.xgp.company.结构性模式.代理模式.静态代理.demo1; public class client { public static void main(string[] args) { /* //直接找房东 host host = new host(); host.rent();*/ //通过代理去租房子 //房东要租房子 host host = new host(); //代理 //中介帮房东租房子,但是,中介一半都会有一些附属操作 proxy proxy = new proxy(host); proxy.rent(); } }
运行结果:
中介代理看房 房东要出租房子! 收中介费 签合同
2.3、分析:
代理模式的好处
- 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务。
- 公共的业务交给了代理角色去完成,实现了业务的分工。
- 公共业务发生扩展的时候,方便集中管理。
缺点:
- 一个真实角色就会产生一个代理的角色,代码量翻倍,开发效率变低。
2.4、例1(增删改查业务的演示)
2.4.1、编写service的抽象类
package com.xgp.company.结构性模式.代理模式.静态代理.demo2; public interface userservice { void add(); void del(); void update(); void query(); }
2.4.2、编写service的实现类
package com.xgp.company.结构性模式.代理模式.静态代理.demo2; /** * 真实对象 */ public class userserviceimpl implements userservice { @override public void add() { system.out.println("增加了一个用户"); } @override public void del() { system.out.println("删除了一个用户"); } @override public void update() { system.out.println("更新了一个用户"); } @override public void query() { system.out.println("查询了一个用户"); } }
2.4.3、如果此时想不改变原有的代码,而增加方法日志打印的功能,此时代理诞生
package com.xgp.company.结构性模式.代理模式.静态代理.demo2; /** * 代理角色,增加日志的功能 */ public class userserviceproxy implements userservice { private userservice userservice; public void setuserservice(userservice userservice) { this.userservice = userservice; } @override public void add() { userservice.add(); log("add"); } @override public void del() { userservice.del(); log("del"); } @override public void update() { userservice.update(); log("update"); } @override public void query() { userservice.query(); log("query"); } public void log(string msg) { system.out.println("使用了" + msg + "方法!"); } }
2.4.4、编写客户端类,使用service的方法,并打印日志
package com.xgp.company.结构性模式.代理模式.静态代理.demo2; public class client { public static void main(string[] args) { userservice userservice = new userserviceimpl(); userserviceproxy proxy = new userserviceproxy(); proxy.setuserservice(userservice); proxy.add(); proxy.del(); proxy.update(); proxy.query(); } }
运行结果:
增加了一个用户 使用了add方法! 删除了一个用户 使用了del方法! 更新了一个用户 使用了update方法! 查询了一个用户 使用了query方法!
2.5、反思:在实际的业务中,横向开发的好处
可以保证原有代码的可行性,不会对软件原来的版本进行破坏,向过去兼容。
3、动态代理
3.1、动态代理的特点
- 动态代理和静态代理一样
- 动态代理的代理类是动态生成的,不是我们直接写的
3.2、动态代理实现方式的分类
- 基于接口——jdk动态代理(本节需要讲述的方式)
- 基于类:cglib
- java字节码实现:javasist
3.3、需要了解的两个类
- proxy:代理类
- invocationhandler:调用处理程序类
具体的使用参照java的api
3.4、例1——房东租房的例子
3.4.1、房东的接口和实现类不变
3.4.2、实现自动生成代理的类
package com.xgp.company.结构性模式.代理模式.动态代理.demo1; import java.lang.reflect.invocationhandler; import java.lang.reflect.method; import java.lang.reflect.proxy; /** * 等下我们会用这个类,自动生成代理类 */ public class proxyinvocationhandler implements invocationhandler { /** * 被代理的接口 */ private rent rent; public void setrent(rent rent) { this.rent = rent; } /** * 获得一个代理 * @return */ public object getproxy() { return proxy.newproxyinstance(this.getclass().getclassloader(),rent.getclass().getinterfaces(),this); } /** * 处理代理实例,并放回结果 * @param proxy * @param method * @param args * @return * @throws throwable */ @override public object invoke(object proxy, method method, object[] args) throws throwable { //用反射来执行方法 seehouse(); //调用代理自身的方法 //动态代理的本质,就是使用反射机制来实现 object result = method.invoke(rent, args); fare(); hetong(); return result; } public void seehouse() { system.out.println("中介带看房子!"); } //收中介费 public void fare() { system.out.println("收中介费"); } public void hetong() { system.out.println("签合同"); } }
3.4.3、实现客户端使用代理来租房子
package com.xgp.company.结构性模式.代理模式.动态代理.demo1; public class client { public static void main(string[] args) { //真实角色 host host = new host(); //代理角色 proxyinvocationhandler pih = new proxyinvocationhandler(); //通过调用程序处理角色,来处理我们要调用的接口对象 pih.setrent(host); //放回代理类 //这里的代理类就是动态生成的,我们并没有写他 rent proxy = (rent) pih.getproxy(); proxy.rent(); } }
运行结果:
中介带看房子! 房东要出租房子! 收中介费 签合同
3.5、例2——增删改查的例子
3.5.1、先来实现一个万能的代理生成类
package com.xgp.company.结构性模式.代理模式.动态代理.demo2; import java.lang.reflect.invocationhandler; import java.lang.reflect.method; import java.lang.reflect.proxy; /** * 万能代理类 */ public class proxyinvocationhandler implements invocationhandler { /** * 被代理的接口 */ private object target; public void settarget(object target) { this.target = target; } /** * 获得一个代理 * @return */ public object getproxy() { return proxy.newproxyinstance(this.getclass().getclassloader(),target.getclass().getinterfaces(),this); } /** * 处理代理实例,并放回结果 * @param proxy * @param method * @param args * @return * @throws throwable */ @override public object invoke(object proxy, method method, object[] args) throws throwable { //用反射来执行方法 //动态代理的本质,就是使用反射机制来实现 object result = method.invoke(target, args); log(method.getname()); return result; } public void log(string msg) { system.out.println("使用了" + msg + "方法!"); } }
也就是将上一个例子的具体实现类——房东类,替换成object类
3.5.2、userservice的接口和实现类不变
3.5.3、编写客户端类使用代理调用增删改查方法
package com.xgp.company.结构性模式.代理模式.动态代理.demo2; public class client { public static void main(string[] args) { //真实角色 userservice userservice = new userserviceimpl(); //代理角色 proxyinvocationhandler pih = new proxyinvocationhandler(); pih.settarget(userservice); userservice proxy = (userservice) pih.getproxy(); proxy.add(); proxy.del(); proxy.update(); proxy.query(); } }
运行结果:
增加了一个用户 使用了add方法! 删除了一个用户 使用了del方法! 更新了一个用户 使用了update方法! 查询了一个用户 使用了query方法!
3.6、弊端分析:
虽然使用动态代理能够节省代码量,并且实现静态代理的全部优点。但是,动态代理的核心是反射技术,通过反射技术调用方法效率较大,因此也可能影响系统效率。
3.7、动态代理的好处
一个动态代理的是一个接口,一般就是对应的一类业务。
上一篇: js实现简单日历效果
下一篇: 10 分钟从零搭建个人博客