设计模式类别
我们之前一直弄的单例,工厂,原型还有建造者模式,都是创建型模式,就是都是针对对象的创建来设计的。
我们这边的代理模式是结构型模式,这种模式不用担心什么对象创建的,而是用来多个对象如何相互配合组成合适的结构来实现代码的解耦的设计模式,引入这个概念后,每当我们来一个新的设计模式都会说他属于什么类似的设计模式。
这种设计模式类别一共就三种,前者我们常见的创建型设计模式,还有结构型设计模式和行为型设计模式。
代理模式
代理模式的基本知识
代理模式可以对比我们所说的中介或者说中间商,我们不用中间商可不可以买车,买房这些,那一定是可以的,但是由于我们受到时间,资源等实际情况限制导致我们,只能减少其他的成本借助中介,来做我们的代理,去买房买车。
对比我们的代码,就是我们希望我们的业务代码更加的集中业务方面,不要掺杂其他的东西,比如说日志,发送消息,审批流这些扩展类的,类似AOP,AOP就是代理的一个非常有代表性的例子。
代理模式应用场景很多:代理模式最常用的一个应用场景就是,在业务系统中开发一些非功能性需求,比如:监控、统计、鉴权、限流、事务、幂等、日志。我们将这些附加功能与业务功能解耦,放到代理类中统一处理,让程序员只需要关注业务方面的开发。
代理模式还可以用在 RPC、缓存等应用场景中
代理的原理和组成
通过上个图,基本就说明了代理的组成部分,主题,实现主题,和代理类。
一般来说经典的静态代理模式一般来说是:主题是一个接口,实现主题,和代理类都是来实现这个接口的,那怎么样去使用代理呢?很简单,当client调用的时候调用代理类,代理类的构建方法是由实现主题来构成的,我们就可以代理。
大致如下
主题
package com.example.test.proxy.normal;
/**
* @Author: zhangpeng
* @Description: 静态代理:买房子的抽象主题 subject
* @Date: 2022/6/8
*/
public interface HouseService {
public void saleHouse();
}
实现主题
package com.example.test.proxy.normal;
/**
* @Author: zhangpeng
* @Description: 静态代理:买房子这个实际业务的实现主题subjext
* @Date: 2022/6/8
*/
public class HouseServiceImpl implements HouseService{
@Override
public void saleHouse() {
System.out.println("-----------买房子的具体业务start------------");
System.out.println("审查资格");
System.out.println("贷款");
System.out.println("房票,验收,拿钥匙");
System.out.println("-----------买房子的具体业务end------------");
}
}
代理类
package com.example.test.proxy.normal;
/**
* @Author: zhangpeng
* @Description:
* @Date: 2022/6/8
*/
public class ProxyHouseAgent implements HouseService {
//具体主题要被代理起来
private HouseServiceImpl houseServiceImpl;
public ProxyHouseAgent (HouseServiceImpl houseService){
this.houseServiceImpl = houseService;
}
@Override
public void saleHouse() {
System.out.println("带你看房-----------");
System.out.println("你很满意");
houseServiceImpl.saleHouse();
System.out.println("佣金到手,哈哈哈");
}
}
我们的client使用如下
package com.example.test.proxy.normal;
/**
* @Author: zhangpeng
* @Description:
* @Date: 2022/6/8
*/
public class HouseTest {
public static void main(String[] args) {
HouseService houseService = new ProxyHouseAgent(new HouseServiceImpl());
houseService.saleHouse();
}
}
其他特殊的代理模式
代理模式非常常用,但是有时候有些情况会有特殊要求,比如说我们想通过扩展第三方功能来代理,但是我们又不能修改第三方模块,也就是不能通过接口来实现代理模式扩展,那我们可以通过继承的方式来实现
示例代码:
关于通过继承来实现代理
还有就是强制代理,就是这些方法只能通过代理才能调用,不能直接去使用实现主题。
除了这些,最大的代理模式其实是动态代理,Java的动态代理是通过反射,AOP就是一种非常不错的范例。别的语言实际上也可以,但是没有Java这么方便,可能要自己先实现自己的反射才行,或者要动态指针改变来完成。
这里是一个关于Java的代理类的实现代码
这里主要的还是内部类实现了InvocationHandler ,然后根据创建的代理类代理参数传递过来的参数。
public class MetricsCollectorProxy {
private MetricsCollector metricsCollector;
public MetricsCollectorProxy() {
this.metricsCollector = new MetricsCollector();
}
public Object createProxy(Object proxiedObject) {
Class<?>[] interfaces = proxiedObject.getClass().getInterfaces();
DynamicProxyHandler handler = new DynamicProxyHandler(proxiedObject);
return Proxy.newProxyInstance(proxiedObject.getClass().getClassLoader(), interfaces, handler);
}
private class DynamicProxyHandler implements InvocationHandler {
private Object proxiedObject;
public DynamicProxyHandler(Object proxiedObject) {
this.proxiedObject = proxiedObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long startTimestamp = System.currentTimeMillis();
Object result = method.invoke(proxiedObject, args);
long endTimeStamp = System.currentTimeMillis();
long responseTime = endTimeStamp - startTimestamp;
String apiName = proxiedObject.getClass().getName() + ":" + method.getName();
RequestInfo requestInfo = new RequestInfo(apiName, responseTime, startTimestamp);
metricsCollector.recordRequest(requestInfo);
return result;
}
}
}
//MetricsCollectorProxy使用举例
MetricsCollectorProxy proxy = new MetricsCollectorProxy();
IUserController userController = (IUserController) proxy.createProxy(new UserController());
PS:
代理模式和装饰器模式,但从静态代理上看二者差不多,从使用上理解就是代理就是添加功能,装饰器模式是功能的加强。