[设计模式]代理模式、适配器模式与装饰器模式

代理模式、适配器模式与装饰器模式

这三种设计模式在代码形式上十分相似。但是为了解决不同的问题而提出的:

  • 代理模式
    • 代理模式在不改变原始接口的条件下,为原始类控制访问、新增一些业务无关的功能。
  • 适配器模式
    • 将不兼容的接口转换为可兼容的接口。(一种以修正为目的的设计模式)。
  • 装饰器模式
    • 装饰器模式是对原始类的功能进行增强,支持多个装饰类的嵌套增强。

代理模式

静态代理

  • 基于接口,若被代理类有接口,那么通常我们的代理类会实现与之一样的接口,注入被代理类,并在实现时,对被代理类进行增强。
  • 基于继承,有些被代理类并没有接口,因此只能使用继承的方式进行扩展。

动态代理

静态代理的问题: 当我们有非常多实现了不同接口的类需要被代理的时候,静态代理的方式就显得非常麻烦。我们需要给每个被代理类实现相同的代理逻辑,但代码大多数都是重复的,我们可以使用反射进行动态代理来解决这一问题。

动态代理Java实现

我们需要实现InvocationHandler 接口。

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 Th
		long startTimestamp = System.currentTimeMillis();
		Object result = method.invoke(proxiedObject, args);
		long endTimeStamp = System.currentTimeMillis();
		long responseTime = endTimeStamp - startTimestamp;
		String apiName = proxiedObject.getClass().getName() + ":" + method.getNam
		RequestInfo requestInfo = new RequestInfo(apiName, responseTime, startTim
		metricsCollector.recordRequest(requestInfo);
		return result;
	}
}

实现完成后,将这个实现,以及被代理类的类加载器、被代理类的接口一同传入Proxy类的静态方法newProxyinstance中,就可以动态的创建代理类了。

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

代理模式的应用

  1. 非业务逻辑的剥离
    1. 对于日志、缓存读写、性能统计等非业务逻辑相关的代码,可以使用统一的代理类进行管理。
  2. RPC框架消费者调用时
    1. RPC调用时,作为消费方,之所以能像调用本地方法一样调用服务端的远程方法,是因为这里使用代理模式为我们屏蔽了服务提供方寻址、请求序列化、结果反序列化等过程。

适配器模式

基于类

简单来说,就是定义一个适配器接口,并继承需要被适配的类,然后实现适配器接口的相应方法。在实现接口的方法时,我们只需要实现那些需要被改造的旧接口,对于符合要求的旧接口,可以继续沿用父类方法。(因此,如果需要适配的对象接口很多,并且和新接口定义大部分都相同,那么可以直接使用基于类的实现)

基于实现

基于实现的方法,是将被适配的类注入进来,再进行相应改造的方式。相较基于类的方式,更灵活。如果新旧接口存在较多的不一致,推荐使用基于实现的方式,会更加灵活。

使用场景

  1. 封装旧系统的api
    1. 方法名称语义不清晰?
    2. 参数过多?
    3. 性能过低?
  2. 替换外部依赖
  3. 兼容老版本

实际应用

比如slf4j就是一套统一不同底层日志包的接口。此外,考虑到不同日志包的api存在的不同,slf4j还提供了相应的适配器,来统一api管理。

装饰器模式

posted @ 2022-09-04 19:12  XinStar  阅读(251)  评论(0编辑  收藏  举报