设计模式的分类
我们都知道有 23 种设计模式,这 23 种设计模式可分为如下三类:
设计模式系列文章传送门
设计模式的 7 大原则
设计模式–单例模式【创建型模式】
设计模式–工厂方法模式【创建型模式】
设计模式–抽象工厂模式【创建型模式】
设计模式–建造者模式【创建型模式】
设计模式–原型模式【创建型模式】
设计模式–适配器模式【结构型模式】
设计模式–装饰器模式【结构型模式】
什么是代理模式
代理模式属于结构型设计模式,其核心思想是为其他对象提供一种代理来完成对这个对象的访问,代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式的分类
代理模式可以分为三类,如下:
代理模式的优缺点
优点:
缺点:
代理模式的组成
我们以生活中的租房为案例来演示静态代理,假设我是房东我有房子需要出租,但是我没有时间去打理出租的这个过程,因为我委托访房产中介来代理我出租房子,这里面我要出租房子就是具体主题,而中介就是代理角色。
House (抽象主题)
定义了一个需要出租房屋的方法,也就是抽象主题,代码如下:
public interface House {
//出租房子
void rentHouse();
}
MyHouse(具体主题)
我有房子要出租,是具体主题,其实现了抽象主题,代码如下:
public class MyHouse implements House{
@Override
public void rentHouse() {
System.out.println("租房的客户来了");
}
}
HouseRentProxy(静态代理)
我要出租房子,而我又没有时间开打理,因此将此业务委托给中介代理,也就是代理对象,代码如下:
public class HouseRentProxy implements House {
private MyHouse myHouse;
public HouseRentProxy(MyHouse myHouse) {
this.myHouse = myHouse;
}
@Override
public void rentHouse() {
System.out.println("委托代理中介来帮我组房子");
myHouse.rentHouse();
}
}
可以看到,静态代理对象内部含有对真实主题的引用
ClientHouse(客户端)
假设有一个客户要来租房,我通过代理对象完成房屋的出租,代码如下:
public class ClientHouse {
public static void main(String[] args) {
//具体对象
MyHouse myHouse = new MyHouse();
//代理对象
HouseRentProxy houseRentProxy = new HouseRentProxy(myHouse);
//同多代理对象来租房
houseRentProxy.rentHouse();
}
}
执行结果如下:
委托代理中介来帮我组房子
租房的客户来了
可以看到我们通过代理对象完成了房屋的出租。
静态代理使用场景
在 Java 中动态代理的实现又分为 JDK 动态代理和 CGLib 动态代理,我们接下来分开分析。
JDK 动态代理
JDK 动态代理是基于接口的代理方式,它是在程序运行时动态生成代理类,也就是说我们在编写代码时并不知道具体代理的是什么类,而是在程序运行时动态生成,是 Java 标准库中提供的一种代理方法,代理对象实现和原始类一样的接口,并将方法调用转发给被代理对象,同时还可以在方法调用前后执行额外的增强处理,JDK 动态代理通过反射机制实现代理功能。
JDK 动态代理的代理类实现了 InvocationHandler 接口,其目的是对具体主题的方法的增强,InvocationHandler 接口中只有一个 invoke 方法,动态代理对象中的映射方法在执行时都是调用的 InvocationHandler 接口中的 invoke 方法,在调用 invoke 方法时,动态代理对象会将 被代理对象的方法和动态代理对象映射的方法的参数传递给 InvocationHandler 的 invoke 方法, invoke 方法的实现是由开发人员编写的,这样开发人员就可以在被代理对象的方法执行前后进行功能增强。
House (抽象主题)
定义了一个需要出租房屋的方法,也就是抽象主题,代码如下:
public interface House {
//出租房子
void rentHouse();
}
MyHouse(具体主题)
我有房子要出租,是具体主题,其实现了抽象主题,代码如下:
public class MyHouse implements House{
@Override
public void rentHouse() {
System.out.println("租房的客户来了");
}
}
MyHouseJdkProxy(动态代理)
JDK 动态代理类,代码如下:
public class MyHouseJdkProxy implements InvocationHandler {
private Object target;
public MyHouseJdkProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理中介帮我找到了租户");
Object invoke = method.invoke(target, args);
System.out.println("代理中介帮我完成了租赁签约");
return invoke;
}
}
ClientHouse(客户端)
客户端使用 JDK 动态代理类完成房屋出租功能,代码如下:
public class ClientHouse {
public static void main(String[] args) {
//被代理类对象
MyHouse myHouse = new MyHouse();
//被代理对象类加载器
ClassLoader classLoader = myHouse.getClass().getClassLoader();
//被代理对象的方法
Class<?>[] interfaces = myHouse.getClass().getInterfaces();
//获取代理对象
MyHouseJdkProxy myHouseJdkProxy = new MyHouseJdkProxy(myHouse);
//生成代理对象
House myHouseProxy = (House) Proxy.newProxyInstance(classLoader, interfaces, myHouseJdkProxy);
myHouseProxy.rentHouse();
}
}
动态代理执行结果如下:
代理中介帮我找到了租户
租房的客户来了
代理中介帮我完成了租赁签约
可以看到我们使用代理类完成了房屋的出租,并且完成了房屋出租前后的增加实现。
CGLIB 动态代理
CGLIB 代理是在运行时动态生成代理类的方式,它使用的是 cglib 库,和 JDK 动态代理相比,它不是动态的生成一个实现了接口的代理类,
而是在运行时动态生成目标类的子类作为代理类,并重写其中的方法来实现代理功能,与 JDK 动态代理不同,CGLIB动态代理没有实现接口,CGLIB 代理是基于类的代理。
CGLIB 代理实现步骤:
这里我们同样使用出租房屋这个场景来演示 CGLIB 代理。
MyHouse(具体主题)
我们根据出租房屋抽象出具体主题 MyHouse,代码如下:
public class MyHouse {
public void rentHouse() {
System.out.println("租房的客户来了");
}
}
可以看到这里区别于 JDK 动态代理,这里没有实现接口,就只是定义了一个普通的类。
MyHouseCglibProxy(动态代理)
CGLIB 动态代理增强类,代码如下:
public class MyHouseCglibProxy implements MethodInterceptor {
@Override
public Object intercept(Object object, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("代理中介帮我找到了租户");
Object invokeSuper = methodProxy.invokeSuper(object, objects);
System.out.println("代理中介帮我完成了租赁签约");
return invokeSuper;
}
}
ClientHouse(客户端)
客户端使用 CGLIB 动态代理类完成房屋出租功能,代码如下:
public class ClientHouse {
public static void main(String[] args) {
//cglig 代理的增强类
Enhancer enhancer=new Enhancer();
//设置被代理类 cgliba 根据该类去生成子类
enhancer.setSuperclass(MyHouse.class);
//设置代理类 也就是增强方法
enhancer.setCallback(new MyHouseCglibProxy());
//生成代理对象
MyHouse myHouseProxy = (MyHouse)enhancer.create();
myHouseProxy.rentHouse();
}
}
执行结果如下:
代理中介帮我找到了租户
租房的客户来了
代理中介帮我完成了租赁签约
可以看到我们使用 CGLIB 代理实现了功能增强
动态代理适用场景
总结:本篇我们简单分享了结构型设计模式–代理模式,并举例分析了静态代理和动态代理的具体实现,希望可以帮助到有需要的朋友。
如有不正确的地方欢迎各位指出纠正。