文章目录
一、前言
有时候不想动脑子,就懒得看源码又不像浪费时间所以会看看书,但是又记不住,所以决定开始写"抄书"系列。本系列大部分内容都是来源于《 图解设计模式》(【日】结城浩 著),内容仅用于个人学习记录,可随意转载。
二、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
如有侵扰,联系删除。 内容仅用于自我记录学习使用。如有错误,欢迎指正