Spring的九种设计模式学习笔记
简介
将一个类的接口转换成客户希望的另外一个接口。Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。——Gang of Four
- 核心思想 :将类自己的接口包裹在一个已存在的类中,在两种接口之间创建一个混合接口,以达到组合两个不相干的类并兼容的目的;
- 组成:source类(拥有一个方法),Targetable(目标接口)
- 分类:根据适配器的实现方式,把适配器分成对象适配器和类适配器。对象适配器模式,依赖于对象的组合,都是采用对象组合的方式,也就是对象适配器实现的方式;类适配器,采用多重继承对一个接口与另一个接口进行匹配。由于 Java 不支持多重继承,所以到目前为止还没有涉及。但可以通过让适配器去实现 Target 接口的方式来实现。(双向适配器:同时实现了 Target 和 Adaptee 的接口,使得双向适配器可以在 Target 或 Adaptee 被使用的地方使用,以提供对所有客户的透明性。尤其在两个不同的客户需要用不同的地方查看同一个对象时,适合使用双向适配器。)
- 优点:适配器模式也是一种包装模式,它与装饰模式同样具有包装的功能,此外,对象适配器模式还具有委托的意思。总的来说,适配器模式属于补偿模式,专用来在系统后期扩展、修改时使用。将目标类和适配者类解耦,增加了类的透明性和复用性,另外灵活性和拓展性都非常好,符合开闭原则。
- 缺点:过多的使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
实例演示
// Source类 耳机插口(圆)
public interface RoundPort {
void useRoundPort();
}
//Source类 手机插口(扁平)
public interface FlatPort {
void useFlatPort();
}
//Targetable 转换头(新智能机的转换线)
@AllArgsConstructor //生成有参构造器 lombok
public calss RoundToFlat implements RoundPort {
private FlatPort flatPort; //扁口
public void useRoundPort(){
this.flatPort.useFlatPort();
}
}
//Client 代理类
public class Client {
public static void main(String[] args){
FlatPort flatPort = new FlatPort(){
()->System.out.println("使用耳机听音乐")
}
RoundPort roundPort = new RoundToFlat(flatPort);
roundPort.useRoundPort();
}
}
spring源码演示
在 Spring 的 AOP 里通过使用的 Advice(通知)来增强被代理类的功能。Spring 实现这一 AOP 功能的原理就使用代理模式(1、JDK 动态代理。2、CGLib 字节码生成技术代理。)对类进行方法级别的切面增强,即,生成被代理类的代理类,并在代理类的方法前,设置拦截器,通过执行拦截器中的内容增强了代理方法的功能,实现的面向切面编程。
Advice(通知)的类型有:BeforeAdvice、AfterReturningAdvice、ThrowSadvice 等。每个类型 Advice(通知)都有对应的拦截器,MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor、ThrowsAdviceInterceptor。Spring 需要将每个 Advice(通知)都封装成对应的拦截器类型,返回给容器,所以需要使用适配器模式对 Advice 进行转换。
//MethodBeforeAdvice 类 ---Source类
public interface MethodBeforeAdvice extends BeforeAdvice {
void before(Method method, Object[] args, Object target) throws Throwable;
}
//Adapter 类接口 ---Source类
public interface AdvisorAdapter {
boolean supportsAdvice(Advice advice);
MethodInterceptor getInterceptor(Advisor advisor);
}
//MethodBeforeAdviceAdapter 类 ---Targetable 转换头
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
public boolean supportsAdvice(Advice advice) {
return (advice instanceof MethodBeforeAdvice);
}
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
}
//DefaultAdvisorAdapterRegistry 类
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
private final List<AdvisorAdapter> adapters = new ArrayList<AdvisorAdapter>(3);
/**
* Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters.
*/
public DefaultAdvisorAdapterRegistry() {//这里注册了适配器
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
if (!(adviceObject instanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
if (advice instanceof MethodInterceptor) {
// So well-known it doesn't even need an adapter.
return new DefaultPointcutAdvisor(advice);
}
for (AdvisorAdapter adapter : this.adapters) {
// Check that it is supported.
if (adapter.supportsAdvice(advice)) {//这里调用了适配器的方法
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {//这里调用了适配器的方法
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
}
public void registerAdvisorAdapter(AdvisorAdapter adapter) {
this.adapters.add(adapter);
}
}
个人总结和使用场景
在开发时,也就是系统的方法和数据都正确,但接口不兼容时,我们这时应该考虑用适配器,目的是使控制范围之外的一个原有对象与某个接口兼容。适配器模式主要应用于复用一些现存的类,但是接口又与复用环境要求不兼容的情况。比如在需要对早期代码复用一些功能等应用上很有实际价值。适用场景大致包含三类:
1、已经存在的类的接口不符合我们的需求;
2、创建一个可以复用的类,使得该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作;
3、在不对每一个都进行子类化以匹配它们的接口的情况下,使用一些已经存在的子类。
适配器