23种设计模式——最好理解的代理模式
大家好,我是
方圆
,小小的代理模式
一、 到底啥是代理模式?
用官方的话说,代理模式就是为目标对象提供另外一种访问方式,通过访问代理对象来间接访问目标对象。
我们来打个比方,简单点儿描述,比如我是房东,我要出租房屋,以前呢我直接租给住户,这样就是没有代理。但是现在我觉得我直接找客户出租房屋很麻烦,所以我就把房子交给中介,让中介帮我出租房子,我只管提供房子,中介帮我做带客户看房啊、收费等其他事物,这样,房东有了代理,这就是代理模式。
从这也能看出代理模式的一点好处,让房东专注于提供房子,其他事物由代理做,反映到程序中,就是,能让service层专注于提供服务,采用代理模式来实现其他事物,在不改变service层代码的情况下,提供了其他的功能。
二、静态代理模式
我们还是拿租房这个简单的例子来讲解
这是一个接口,房东实现这个接口,来提供租房子的业务
//租房
public interface Rent {void RentHouse();
}
这个是房东类,在程序中就位于service层
//房东
public class Host implements Rent{public void RentHouse() {System.out.println("房东出租房屋给客户");}
}
//我是代理,房屋中介
public class Proxy implements Rent{private Host host;public void setHost(Host host) {this.host = host;}public void RentHouse() {host.RentHouse();}
}
这个就是客户类
//客户,要租房子的人
public class Client {public static void main(String[] args) {//在没有中介的时候,直接找房东租房Host host = new Host();host.RentHouse();}
}
,房东直接租房子给客户。
下面,房东要找代理了。
public class Client {public static void main(String[] args) {//在没有中介的时候,直接找房东租房Host host = new Host();//这里是一个代理Proxy proxy = new Proxy();proxy.setHost(host);//房东把房子交给中介//中介代替房东出租房屋,调用出租房的方法//理论上还是房东出租给客户房屋,只不过这件事情被中介给做了proxy.RentHouse();}
}
我们这里没有用房东直接调用租房的方法,而是中介调用,同样实现了租房的功能,这样就实现了静态代理模式。
我们这里总结一下代理模式的好处
- 可以让service层专注于实现自己的业务,也就是房东只专注于提供房子,中介负责向客户出租和一些细枝末节的事情,我们同样可以在中介代码中,添加一下其他方法,并不影响房东的代码
- 要对业务就行扩展时,可修改代理的代码进行添加,而不需要修改service层源码
但是缺点也显而易见,静态嘛,不够灵活,代码冗余,一个service就需要一个代理,使代码翻倍。
为了解决这个缺点就出现了动态代理
三、动态代理模式
我们同样还是需要以上的Rent接口,和Host类
但是这次我们需要创建一个动态代理的类,ProxyInvocationHandler
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class ProxyInvocationHandler implements InvocationHandler {//这个了实现了 InvocationHandler 接口
//每个代理的实例需要实现这个接口,从而来调用处理程序的实现
//invoke handler:翻译为中文就是调用处理程序//我们需要实现租房子的这个接口,所以定义一个变量private Rent rent;public void setRent(Rent rent) {this.rent = rent;}//生成代理类的方法public Object getProxy(){//newProxyInstance() 创建代理实例方法// 这个方法中,第一个参数为Invocation类的类加载器//第二个参数,为要让代理实现的类的接口,也就是要实现租房子的接口//第三个参数,是Invocation类本身Object proxyInstance = Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);return proxyInstance;}//这个invoke方法,官方介绍中说://每一个代理实例Proxy都由一个关联的调用处理程序invoke,//当在代理实例上调用方法时,方法调用将被编码并分配到其调用处理程序的invoke方法//也就是说,当用代理调用方法的时候,这个invoke方法就会帮代理实现方法public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//在这里,invoke会帮助Proxy代理实例来实现方法//其中参数 method就是要实现的方法//方法调用invoke(rent,args)来返回结果//其中参数rent是要被实现方法的接口,args默认填写Object result = method.invoke(rent, args);return result;}
}
下面我们就用客户类来实现一下这个动态代理
public class Client {public static void main(String[] args) {//这里还是有一个房东准备要出租房子Host host = new Host();//创建ProxyInvocationHandler对象,用该对象的方法getProxy()方法创建代理实例//并且该对象实现了InvocationHandler接口,就由了调用处理程序实现的功能,也就是invoke()方法ProxyInvocationHandler handler = new ProxyInvocationHandler();handler.setRent(host); //这里把房东传值给handler中的rent对象,也就是房东把房子交给中介//利用handler对象,调用其中我们写好的getProxy方法,来实例代理,也就是中介Rent proxy = (Rent) handler.getProxy();//这里中介就帮房东出租房子了,也就实现了我们的代理模式proxy.RentHouse();}
}
动态代理解决了静态代理代码冗余的缺点
如果我们将动态代理类中的代码进行修改
将其中这段代码改为private Rent rent;public void setRent(Rent rent) {this.rent = rent;}
如下private Object object;public void setObject(Object object) {this.object = object;}
那么,这样它就成了一个万能的代理,能传入任何类型的接口,那么他就什么都能代理了。
四、 cglib动态代理代码示例
用cglib我们需要导包,如下
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.2.12</version></dependency>
cglib动态代理与JDK动态代理的区别:cglib无需强制实现接口,其生成的代理类是被代理类的子类
我们创建一个需要被代理的类Rent
public class Rent {public void rentHouse(){System.out.println("出租房屋");}
}
随后我们创建cglib动态代理,实现的是MethodInterceptor接口
import java.lang.reflect.Method;public class RentCglib implements MethodInterceptor {//被代理的对象private Object service;//注入被代理的对象public void setService(Object service) {this.service = service;}public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {//可以在这里写上增加的功能System.out.println("代理带房客看房");return method.invoke(service, objects);}
}
最后我们写一个测试类,进行测试
import net.sf.cglib.proxy.Enhancer;public class Test {public static void main(String[] args) {//创建租房服务Rent rent = new Rent();//注入租房的类RentCglib rentCglib = new RentCglib();rentCglib.setService(rent);//创建增强器,用来创建动态代理实例Enhancer enhancer = new Enhancer();//注入动态代理要代理的类enhancer.setSuperclass(rent.getClass());//设置回调enhancer.setCallback(rentCglib);//创建动态代理实例Rent rentService = (Rent) enhancer.create();rentService.rentHouse();}
}
输出结果如下
参考文献
b站狂神说
经过一次修改,可读性比之前好了,但是还需要自己写出来才能掌握
23种设计模式——最好理解的代理模式相关推荐
- 23种设计模式学习记录之代理模式
想说的话: 在大学的时候曾经学过这23种设计模式,但是那时没啥编程经验,糊里糊涂过了一遍,没多久就忘记了,工作之后将精力主要集中在学习新技术上,比如springboot,cloud,docker,vu ...
- 23种设计模式(7)-代理模式
定义: 为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用 角色: 1, 抽象角色:声明真实对象 ...
- 23种设计模式通俗理解
23种设计模式通俗理解 1.根据目的来分 2.根据作用范围来分 3.GoF的23种设计模式的功能 1.FACTORY 工厂方法 2.BUILDER建造者模式 3.FACTORY METHOD抽象工厂 ...
- JavaScript 23 种设计模式之 4 抽象工厂模式
JavaScript 23 种设计模式之 4 抽象工厂模式 概念与特点 结构与实现 应用场景 应用实例 总结 概念与特点 概念: 提供一组相关或相互依赖对象的接口.抽象工厂模式是工厂方法模式的升级版, ...
- 23种设计模式之单例模式、工厂模式、原型模式、建造者模式
系列文章目录 第一章:程序设计原则-单一职责.接口隔离.依赖倒置.里式替换 第二章:程序设计原则-开闭原则.迪米特法则.合成复用原则 文章目录 系列文章目录 一.设计模式简单介绍 1.1.什么是设计模 ...
- Unity实现:23种设计模式、《游戏编程模式》
目录 一.23种设计模式在Unity实现 Creational Patterns 创建型模式(5种) 工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式 Structural Patterns ...
- 23种设计模式(十一)外观模式(阁瑞钛伦特软件-九耶实训)
常说的设计模式是23种设计模式,分为3大类: 创建型模式5种:工厂方法.抽象工厂.单例.建造者.原型 结构型模式7种:适配器.代理.桥接.装饰者.外观.享元.组合 行为型模式11种:模板方法.解释器. ...
- 23种设计模式(第二章创建者模式5种)
第二章创建者模式 单例模式 单例模式有 3 个特点: 单例类只有一个实例对象: 该单例对象必须由单例类自行创建: 单例类对外提供一个访问该单例的全局访问点. 单例模式的实现 单例设计模式分类两种: ...
- 23种设计模式 -----Day01:简单工厂模式
目录 前言 1.设计模式(Design pattern)定义 2.为什么要使用设计模式(使用设计模式的意义) 3.设计原则 a.单一职责原则 b.开放封闭原则 c.里氏代换原则 d.迪米特法则 e.依 ...
- 【23种设计模式专题】二 工厂模式
程序猿学社的GitHub,欢迎Star github技术专题 本文已记录到github 文章目录 前言 小故事 传统方式 简单工厂(第一种) 工厂方法模式(第二种) 抽象工厂模式(第三种) 使用工厂方 ...
最新文章
- ajax请求必须打断点才能成功,Jquery等待ajax执行完毕继续执行(断点调试正常,运行异常)...
- asp.net cache
- 在数据库插入带小数点数据的问题
- go语言查询某个值是否在数组中_go语言中的数组
- 37 FI配置-财务会计-固定资产-组织结构-复制参考折旧表/折旧范围表
- Wise Package Studio介绍
- Memcache 安装
- JAVA API中文在线帮助文档
- php screw.so,php screw加密
- 看透说破:客户服务首解率(FCR)的迷思
- MongoDB修改器使用
- c++ 写一个复数计算器
- 3D游戏编程与设计-井字棋
- Intellij IDEA优化配置(1)------Darcula主题的选择以及字体和颜色配置(基于Intellij IDEA 2019.1)
- python打开excel执行vba代码_“Python替代Excel Vba”系列(终):vba中调用Python
- 文献笔记--相关:无线通信、安全加密隐私
- python电话号码_Python有效电话号码
- android使用精伦身份证读卡器读身份证
- 【MySQL 8.0 OCP 1Z0-908认证考试】题库精讲--第三讲mysql8.0安装配置升级(中)
- oracle prompt出错,Oracle 用 sqlprompt 修改 sqlplus 提示符
热门文章
- 2022-03-25 Python作业1
- c语言 qt 写小游戏,Qt实现Flappy Bird游戏
- c++/c语言(高质量程序设计指南林锐建议总结)
- 批量Batch and 动量Momentum
- 高效搭建基于dnsmasq通过webui管理的dns服务器
- 7、杂项:蓝牙beacon简述
- TensorFlow Serving Introduction
- C++写入并追加内容到txt中
- 硬盘大于2t linux安装 集群 网络,centos 6在大于2T硬盘上安装系统
- flyaway mysql_golang通用连接池,支持GRPC,RPC,TCP