设计模式① :适应设计模式

一、前言

有时候不想动脑子,就懒得看源码又不像浪费时间所以会看看书,但是又记不住,所以决定开始写"抄书"系列。本系列大部分内容都是来源于《 图解设计模式》(【日】结城浩 著),内容仅用于个人学习记录,可随意转载。

二、Iterator 模式

Iterator 模式 :一个一个遍历

1. 介绍

迭代器模式最常见的使用是使用Java 集合类时, 准确的说是 java.util.Collection 的实现类都具备了迭代器的类型,其实现也非常简单。

迭代器模式中登场的角色有:

  • Iterator(迭代器):该角色负责定义而按顺序逐个遍历元素的接口。以 Java 的实现为例,其接口为 java.util.Iterator
  • ConcreteIterator (具体的迭代器):该角色负责实现 Iterator 角色所定义的接口。如 java.util.ArrayList的内部迭代器java.util.ArrayList.Itr
  • Aggregate(集合):该角色负责定义创建 Iterator 角色的接口。如 java.lang.Iterable
  • ConcreteAggregate(具体的集合) :该角色负责实现 Aggregate角色所定义的接口。如 java.util.ArrayList 。

类图如下:
在这里插入图片描述


以上述内容举个例子如下:

// 集合
public interface Aggregate<T> {
    /**
     * 获取迭代器
     * @return
     */
    Iterator<T> iterator();
}

// 迭代器
public interface Iterator<T> {
    /**
     * 是否存在下一个元素
     * @return
     */
    boolean hasNext();

    /**
     * 获取下一个元素
     * @return
     */
    T next();
}

// 具体的集合
public class ConcreteAggregate implements Aggregate<String> {

    private final String[] designDemos = new String[10];

    public ConcreteAggregate() {
        // 初始化数据集
        for (int i = 0; i < designDemos.length; i++) {
            designDemos[i] = String.valueOf(i);
        }
    }

    public int getLength() {
        return designDemos.length;
    }

    public String get(int index){
        // TODO : 边界校验
        return designDemos[index];
    }

    @Override
    public Iterator<String> iterator() {
        return new ConcreteIterator(this);
    }
}

// 具体的迭代器
public class ConcreteIterator implements Iterator<String> {

    private ConcreteAggregate concreteAggregate;
    private int index = 0;

    // TODO : 入参改造为面向接口
    public ConcreteIterator(ConcreteAggregate concreteAggregate) {
        this.concreteAggregate = concreteAggregate;
    }

    @Override
    public boolean hasNext() {
        return index < concreteAggregate.getLength();
    }

    @Override
    public String next() {
        // TODO : 一些范围校验
        final String info = concreteAggregate.get(index);
        index += 1;
        return info;
    }
}

// 测试类如下:
public class IteratorDemoMain {
    public static void main(String[] args) {
        final Aggregate demoAggregate = new ConcreteAggregate();

        final Iterator<String> iterator = demoAggregate.iterator();

        while (iterator.hasNext()){
            final String next = iterator.next();
            System.out.println("next = " + next);
        }
    }
}

2. 应用

迭代器模式的典型应用就是 Java 中的 Collection 以及其子类,这个由于太熟悉就不再这里赘述。
而在日常使用中,个人也没有自定义过迭代器模式使用。

3. 总结

引入Iterator 设计模式可以将遍历和实现分离开来

如下即使 DemoAggregate 中实现从数组变成了 List 或者其他自定义结构,在这里的遍历都不需要修改:

	public class IteratorDemoMain {
	    public static void main(String[] args) {
       		final Aggregate demoAggregate = new DemoAggregate();
       		
			// 这里的遍历完全不再依赖于 DemoAggregate 
	        final Iterator<String> iterator = demoAggregate.iterator();
	        while (iterator.hasNext()){
	            final String next = iterator.next();
	            System.out.println("next = " + next);
	        }
	    }
	}

相关的设计模式 :

  • Visitor 模式:Iterator 模式 是从集合中一个一个取出元素进行遍历,但是并没有在 Iterator 接口中声明对取出的元素进行何种处理。Visitor 模式则是在遍历元素集合的过程中对元素做相同的处理。因为在遍历集合的过程中对元素进行固定的处理是常用的需求。Visitor 模式正是为了应对这种需求而出现的,在访问元素集合的过程中对元素进行相同的处理,这种模式就是 Visitor 模式。
  • Composite 模式:Composite 模式是具有递归结构的木事,在其中使用 Iterator 模式比较困难
  • Factory Method 模式:在 iterator 方法中生成 Iterator 的实例时可能会使用 Factory Method 模式

三、Adapter 模式

Adapter 模式 :加个适配器以便于复用

1. 介绍

Adapter 模式也被称为 Wrapper模式(包装器模式),适配器模式有两种:

  • 类适配器模式(使用继承的适配器): 类图如下,由实现了 Target 接口 (适配器接口)的 Adapter (适配器类) 通过继承 Adaptee (被适配的类)的方式来对 Adaptee 进行适配。在实际使用时暴露给外界的是 Target 接口,在 Target 的方法中则实现了对 Adaptee 的适配。
    在这里插入图片描述

  • 对象适配器模式(使用委托的适配器):类图如下,Adapter (适配器)通过持有 Adaptee(被适配的类) 来进行适配,外界调用 Target(适配器接口)的方法时实际上则是通过 Adapter 对 Adaptee 进行了适配后的结果。
    在这里插入图片描述

Adapter 模式中登场的角色有:

  • Target (对象) :该角色负责定义而所需的方法。
  • Client (请求者) :该角色负责使用 Target 角色所定义的方法进行具体处理。
  • Adaptee (被适配) :Adaptee 是一个持有既定方法的角色。
  • Adapter (适配) :使用Adaptee角色的方法来满足 Target 角色的需求。

1.1 类适配器模式

该模式意在通过继承 Adaptee 的方式来对其进行适配, 如下:


	public interface Target {
	    void targetMethodA();
	}
	
	public class Adaptee {
	    public void methodA(){
	        System.out.println("Adaptee.methodA");
	    }
	}
	
	public class Adapter extends Adaptee implements Target {
	    @Override
	    public void targetMethodA() {
	        System.out.println("Adapter.targetMethodA");
	        methodA();
	    }
	}
	
	public class Client {
	    public static void main(String[] args) {
	        Target target = new Adapter();
	        target.targetMethodA();
	    }
	}


1.2 对象适配器模式

	public class Adaptee {
	    public void methodA() {
	        System.out.println("Adaptee.methodA");
	    }
	}
	
	public interface Target {
	    void targetMethodA();
	}
	
	
	public class Adapter implements Target {
	
	    private Adaptee adaptee;
	
	    public Adapter(Adaptee adaptee) {
	        this.adaptee = adaptee;
	    }
	
	    @Override
	    public void targetMethodA() {
	        System.out.println("Adapter.targetMethodA");
	        adaptee.methodA();
	        // TODO : do something
	    }
	}
	
	public class Client {
	    public static void main(String[] args) {
	        Target target = new Adapter();
	        target.targetMethodA();
	    }
	}

2. 应用

下面我们来看 适配器模式在现实中的应用,如下:

2.1 AdvisorAdapter

Spring Aop 是通过 Advice 来增强代理类的功能, 在 Advice 的基础上创建了多个子接口和实现类,BeforeAdvice (方法执行前执行)、AfterAdvice(方法执行后执行) 等。如下图:
在这里插入图片描述

实际上Spring 需要 MethodInterceptor 来完成方法拦截。因此,对于 MethodBeforeAdvice、ThrowsAdvice、AfterReturningAdvice 类型本身并非是 MethodInterceptor 类型的 Advice 增加了适配器来转换为对应的 MethodInterceptor (MethodBeforeAdvice 转为 MethodBeforeAdviceInterceptor,ThrowsAdvice 转为 ThrowsAdviceInterceptor,AfterReturningAdvice 转为 AfterReturningAdviceInterceptor)。

Spring Aop 的完整分析流程如有需要详参:Spring源码分析十二:@Aspect方式的AOP上篇 - @EnableAspectJAutoProxy


如下 AfterReturningAdviceAdapter 将 AfterReturningAdvice 转换为 AfterReturningAdviceInterceptor 类型:

class AfterReturningAdviceAdapter implements AdvisorAdapter, Serializable {

	@Override
	public boolean supportsAdvice(Advice advice) {
		return (advice instanceof AfterReturningAdvice);
	}

	@Override
	public MethodInterceptor getInterceptor(Advisor advisor) {
		AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice();
		return new AfterReturningAdviceInterceptor(advice);
	}

}

2.2 HandlerAdapter

在 Spring Mvc 中 由于有多种 HandlerMapping (处理器映射),他们会依据各自的规则扫描并将合适的方法作为自己的处理器。如 RequestMappingHandlerMapping 就是我们常见的会扫描容器中 被 @ResquestMapping 注解修饰的方法并封装成 handler,当我们发起 http 调用如果调用地址匹配到了 RequestMappingHandlerMapping 中的 handler, 则会直接调用handler 来处理该次请求。这便是简化版的 Spring mvc 流程。由于 HandlerMapping 有多种就存在多种 handler,Spring mvc 为了兼容这种情况,则 通过 HandlerAdapter 来对不同的 Handler进行适配。

Spring mvc 完成的分析流程如有需要详参: Spring源码分析二十二:Spring MVC③ DispatcherServlet的逻辑


如下是 HandlerAdapter 的定义:

public interface HandlerAdapter {
	boolean supports(Object handler);
	
	@Nullable
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
	
	long getLastModified(HttpServletRequest request, Object handler);
}

在 DispatcherServlet#getHandlerAdapter 中会获取handler 对应的适配器,在后面通过HandlerAdapter#handle 来处理对应的handler。

	// org.springframework.web.servlet.DispatcherServlet#getHandlerAdapter
	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		if (this.handlerAdapters != null) {
			for (HandlerAdapter adapter : this.handlerAdapters) {
				if (adapter.supports(handler)) {
					return adapter;
				}
			}
		}
		throw new ServletException("No adapter for handler [" + handler +
				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
	}

3. 总结

  • 类适配器模式 : 这种情况感觉和装饰器模式非常类似,区别在于装饰器模式会重写对应的方法来扩展实现,而类适配器模式会直接通过一个新方法来扩展实现。个人一般都使用装饰器模式来解决问题。
  • 对象适配器模式:该模式个人在日常中使用的非常多,尤其是在面对扩展场景时,使用适配器模式可以很好的遵守【开闭原则】,并且代码也很清晰。

相关的设计模式 :

  • Bridge 模式:Adapter 模式用于连接接口(API)不同的类,而 Bridge 模式则用于连接类的功能层次结构与实现层次的结构。
  • Decorator 模式:Adapter 模式用于填补不同接口 (API)之间的缝隙,而 Decorator 模式则是在不改变接口的前提下增加功能。

以上:内容部分参考
《 图解设计模式》
https://blog.csdn.net/qq_37774171/article/details/122643900#t9
如有侵扰,联系删除。 内容仅用于自我记录学习使用。如有错误,欢迎指正

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猫吻鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值