设计模式相关文章
----单例模式原理-JAVA设计模式
----工厂模式原理-JAVA设计模式
代理模式原理-JAVA设计模式
----建造者模式(Bulider模式)详解—JAVA设计模式
代理方式
- 代理模式分为2种
- 静态代理
- 动态代理
一、静态代理
1、介绍
1.1、定义
给目标角色提供一个代理角色,并由代理角色控制对目标角色的引用
1.2、作用
通过引入代理角色的方式来间接访问目标角色
2、 案例解析
2.1、 流程结构
房东出租房子的例子,3个角色:房东----中介----租客
- 抽象角色----房子出租信息(Rent)
- 真实对象----房东(Host)
- 代理类(代理角色)----中介(StaticProxy)
- 租客----(Client)
2.2、 代码实现
1、抽象角色----房子出租信息(Rent)
/**
* 抽象角色---租房
*
* @Auther: curry
* @Description:
*/
public interface Rent {
public void rent();
}
2、真实对象—房东(Host)
/**
* 真实角色---房东---要出租房子
*
* @Auther: curry
* @Description:
*/
public class Host implements Rent{
@Override
public void rent() {
System.out.println("出租房子");
}
}
3、 代理类(代理角色)----中介(StaticProxy)
/**
* 静态代理角色:中介
*/
public class StaticProxy implements Rent {
private Host host;
//无参构造
public StaticProxy() {
}
//有参构造
public StaticProxy(Host host) {
this.host=host;
}
//租房
@Override
public void rent() {
see();
host.rent();
fare();
}
//看房
public void see() {
System.out.println("带租客看房");
}
//中介费
public void fare() {
System.out.println("收中介费");
}
}
4、 租客----(Client)
/**
* 租客----(Client)
*
* @Auther: curry
* @Description:
*/
public class Client {
public static void main(String[] args) {
//真实角色--- //房东要出租房子
Host host=new Host();
//代理实例--中介帮助房东
StaticProxy staticProxy = new StaticProxy(host);
//租客去找中介!
staticProxy.rent();
}
}
5、 测试打印
2.3、分析
在这个过程中,租客直接接触的就是中介,租客不用接触房东,依旧租到了房东的房子,通过代理,这就是所谓的代理模式
3、优缺点
3.1、优点
- 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情
- 公共的业务由代理来完成 . 实现了业务的分工
- 公共业务发生扩展时变得更加集中和方便
3.2、缺点
- 由于在租客和真实角色(房东)之间增加了代理角色(中介),因此会造成请求的处理速度变慢
- 1个静态代理 只服务1种类型的目标角色(房东),若要服务多类型的目标角色,则需要为每种目标角色都实现一个静态代理角色,代码类的增加,从而增加了系统实现的复杂度
3.3、总结
为了解决静态代理的缺点,代理角色和目标角色一对一的关系,才有动态代理的出现
二、动态代理
1、介绍
1.1、定义
- 动态代理的角色和静态代理的一样
- 动态代理的代理类是动态生成的,不同于静态代理是直接生成的
- 动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理
- 基于接口的动态代理----JDK动态代理
- 基于类的动态代理–cglib
1.2、作用
通过引入代理角色的方式来间接访问目标角色
2、 案例解析
2.1、基于接口的动态代理----JDK动态代理
JDK的动态代理需要了解两个类
核心 : InvocationHandler 和Proxy
- invocationHandle接口----调用处理程序
是由代理实例的调用处理程序实现的接口,每个代理实例都有一个关联的调用处理程序,当在代理实列上调用方法时,方法调用将被 分配到其调用处理程序的invoke方法(这一个是JDK翻译给出来的解释
),------简单的来理解就是代理类要实现invocationHandle接口并重写它的invoke方法
- Proxy方法
提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的代理类的超类(也是JDK翻译给出来的解释,后面一句非常拗口
)
2.2、 流程结构
- 抽象角色----房子出租信息(Rent)
- 真实对象----房东(Host)
- 动态代理类----代理角色(DynamicProxy)
- 租客----(Client)
2.3、 代码实现
1、抽象角色----房子出租信息(Rent)
/**
* 抽象角色---租房
*
* @Auther: curry
* @Description:
*/
public interface Rent {
public void rent();
}
2、真实对象—房东(Host)
/**
* 真实角色---房东---要出租房子
*
* @Auther: curry
* @Description:
*/
public class Host implements Rent{
@Override
public void rent() {
System.out.println("出租房子");
}
}
3、动态代理类----代理角色(DynamicProxy)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 动态代理
* 需要实现invocationHandle接口
*/
public class DynamicProxy implements InvocationHandler {
//被代理的接口
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成代理类
public Object getProxy(){
//this.getClass().getClassLoader(),当前对象的类加载器
//rent.getClass().getInterfaces()被代理的接口
//当前对象
Object newProxyInstance = Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
return newProxyInstance;
}
/**
* 处理代理实例并返回结果
* @param o 调用该方法的代理实例
* @param method 所述方法对应于调用代理实例上的接口方法的实例。方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口
* @param objects 包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。原始类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean 。
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
see();
//使用ORM反射机制实现,动态代理的本质
Object invoke = method.invoke(rent, objects);
fare();
return invoke;
}
//看房
public void see() {
System.out.println("带租客看房");
}
//中介费
public void fare() {
System.out.println("收中介费");
}
}
4、 租客----(Client)
package api.web.proxy.dynamicProxy;
/**
* 租客----(Client)
*
* @Auther: curry
* @Description:
*/
public class Client {
public static void main(String[] args) {
//真实角色
Host host=new Host();
//代理实例
DynamicProxy dynamicProxy = new DynamicProxy();
//调用程序处理角色 来处理我们要调用的接口对象
dynamicProxy.setRent(host);
Rent proxy = (Rent)dynamicProxy.getProxy();
proxy.rent();
}
}
5、 测试打印
3、优缺点
3.1、优点
- 只需要1个动态代理类就可以解决创建多个静态代理的问题,避免重复、多余代码
- 设计动态代理类(DynamicProxy)时,不需要显式实现与目标对象类(Host)相同的接口,而是将这种实现推迟到程序运行时由 JVM来实现
- 在使用时(调用目标角色方法时)才会动态创建动态代理类 & 实例,不需要事先实例化
3.1、优点
- 效率低
相比静态代理中 直接调用目标角色方法,动态代理则需要先通过Java反射机制 从而 间接调用目标角色方法 - 应用场景局限
因为 Java 的单继承特性(每个代理类都继承了 Proxy 类),即只能针对接口 创建 代理类,不能针对类 创建代理类
3.3、总结
- 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情
- 公共的业务由代理来完成 . 实现了业务的分工
- 公共业务发生扩展时变得更加集中和方便
- 一个动态代理 , 一般代理某一类业务
- 一个动态代理可以代理多个类,代理的是接口
3.4、应用场景
- 具体应用场景:日志记录、性能统计、安全控制、异常处理等
设计模式相关文章
----单例模式原理-JAVA设计模式
----工厂模式原理-JAVA设计模式
代理模式原理-JAVA设计模式
----建造者模式(Bulider模式)详解—JAVA设计模式