[设计模式]代理模式、适配器模式与装饰器模式
代理模式、适配器模式与装饰器模式
这三种设计模式在代码形式上十分相似。但是为了解决不同的问题而提出的:
- 代理模式
- 代理模式在不改变原始接口的条件下,为原始类控制访问、新增一些业务无关的功能。
- 适配器模式
- 将不兼容的接口转换为可兼容的接口。(一种以修正为目的的设计模式)。
- 装饰器模式
- 装饰器模式是对原始类的功能进行增强,支持多个装饰类的嵌套增强。
代理模式
静态代理
- 基于接口,若被代理类有接口,那么通常我们的代理类会实现与之一样的接口,注入被代理类,并在实现时,对被代理类进行增强。
- 基于继承,有些被代理类并没有接口,因此只能使用继承的方式进行扩展。
动态代理
静态代理的问题: 当我们有非常多实现了不同接口的类需要被代理的时候,静态代理的方式就显得非常麻烦。我们需要给每个被代理类实现相同的代理逻辑,但代码大多数都是重复的,我们可以使用反射进行动态代理来解决这一问题。
动态代理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)
代理模式的应用
- 非业务逻辑的剥离
- 对于日志、缓存读写、性能统计等非业务逻辑相关的代码,可以使用统一的代理类进行管理。
- RPC框架消费者调用时
- RPC调用时,作为消费方,之所以能像调用本地方法一样调用服务端的远程方法,是因为这里使用代理模式为我们屏蔽了服务提供方寻址、请求序列化、结果反序列化等过程。
适配器模式
基于类
简单来说,就是定义一个适配器接口,并继承需要被适配的类,然后实现适配器接口的相应方法。在实现接口的方法时,我们只需要实现那些需要被改造的旧接口,对于符合要求的旧接口,可以继续沿用父类方法。(因此,如果需要适配的对象接口很多,并且和新接口定义大部分都相同,那么可以直接使用基于类的实现)
基于实现
基于实现的方法,是将被适配的类注入进来,再进行相应改造的方式。相较基于类的方式,更灵活。如果新旧接口存在较多的不一致,推荐使用基于实现的方式,会更加灵活。
使用场景
- 封装旧系统的api
- 方法名称语义不清晰?
- 参数过多?
- 性能过低?
- 替换外部依赖
- 兼容老版本
实际应用
比如slf4j就是一套统一不同底层日志包的接口。此外,考虑到不同日志包的api存在的不同,slf4j还提供了相应的适配器,来统一api管理。
装饰器模式
热门相关:斗神战帝 霸皇纪 仗剑高歌 刺客之王 豪门闪婚:帝少的神秘冷妻