zxdsb666. 发表于 2021-4-11 10:44

浅谈设计模式 - 迭代器模式(十一)

# 浅谈设计模式 - 迭代器模式(十一)

# 前言

​        迭代器模式通常只需要知道该模式的实现原理和了解结构图即可,在设计模式当中自己实现的情况几乎是没有的,所以这个模式简单的过一遍。

# 什么是迭代器模式

定义:**提供顺序的方法访问一个聚合对象的各个元素,同时又不会暴露内部的功能**

迭代器模式通过接管遍历的细节,让提供方不必关心迭代的具体细节,只需要提供对应的聚合对象即可。



>迭代器模式和增强的FOR循环:
>
>Jdk1.5之后,将泛型和增强for循环加入到语言体系,可以直接对于集合的内容进行for循环查看,其实本质上还是调用了iterator方法,而java通过语法糖的形式为我们进行的遍历的隐藏。

# 迭代器模式结构图

​        迭代器模式的结构图如下:

​        ![](https://gitee.com/lazyTimes/imageReposity/raw/master/img/20210310215705.png)

```
Aggregate:聚合对象的共同接口,定义了具备遍历功能的聚合对象,通过定义创建迭代器的接口来建立与迭代器的组合
ConcreateAggregate:具体的迭代器实现对象,通过接口方法返回具体的迭代器实现
Iterator:迭代器接口,定义迭代器的统一规范,所以派生类都需要强制按照接口标准执行迭代器的实现。保证迭代器具备相似的行为。
ConcreteIterator:具体的迭代器实现,内部聚合对象的同时,可以扩展迭代器的遍历方式,比如ListIterator。
```



# 迭代器模式特点

+ 迭代器将遍历的细节进行了封装,**聚合对象不需要在关心客户端如何操作内部的变量**,而是通过委托给迭代器的形式交由迭代器去完成具体的遍历细节。
+ 迭代器可以在**不暴露内部结构的同时让外界可以访问到内部的聚合对象**,所以即使是完全不同的对象也可以统一对待和处理。
+ 迭代器是一种职责的转移,将遍历的工作从原本的聚合对象中进行独立,能在**不改动数据结构的同时改变数据的操作方式**。



# 迭代器的注意事项:

1. 需要注意迭代器存在**内部的迭代器**和**外部的迭代器**,内部的迭代器供对象本身使用不对外开放,外部的迭代器通过方法返回给调用方使用。
2. 每个责任对应一个区域,超过区域意味多了一个责任,遍历和数据操作实际上是两个操作,应该区分对待。
3. 注意迭代器是如何体现单一职责的原则,他剥离了遍历对象的功能,将其封装到一个迭代器内部进行使用。
4. 好的迭代器应当具备“快速失败机制”,目的是为了防止操作内部元素的指针越界,同时及时通知客户端遍历异常。
5. **如果想让方法不支持某些功能,最好使用异常机制提醒客户端我不支持某些操作。**



# 案例

​        光有理论还是不够的,这里配合代码讲解迭代器是如何实现解耦聚合对象的遍历的。

## 模拟场景:

​        由于迭代器在实际工作中使用概率 **几乎为0**,这里设置的场景比较简单

​        我们使用window最常见的文件系统来作为案例,我们通常进入不同的磁盘,首先就是对该磁盘下面的第一级目录进行遍历,同时我们根据遍历方式的不同,可以将页面展示为分组,按照时间排序,显示不同的详略信息.....这些功能的本质都是遍历,只不过遍历的形式不同,为了实现对于菜单的不同形式遍历,我们通过定义不同迭代器来完成这一个目标。

​        接着,我们会发现迭代的种类丰富还不够,我们还需要迭代其他的内容,比如任务管理器需要迭代不同的进程,同样也包含了排序的或者隐藏部分进程等等一系列的功能,所以需要让不同的对象可以支撑相似的迭代操作,并且可以自由的替换迭代的方式,当然这部分功能不会放入案例部分,案例部分为简单的迭代器实现。

## 具体实现

​        在进行具体的编码之前,先检查一下需要的基本构建类:

```
Travelsable:定义对象具备迭代的功能接口。
MissionBoard:任务栏,贮存基本的任务信息,提供迭代器供外部展示。
TaskItemlIterator:任务迭代器,用于任务的迭代操作
ConcreteCatalogIterator:目录迭代器的实现具体子类,定义了不同的迭代种类。
TaskItem 任务项,定义一个任务的内容
Computer 电脑,只需要管理任务栏和文件管理器即可。
FileManager 文件管理器,负责管理文件夹的内容
FileIterator 文件迭代器,管理文件夹的迭代操作
FileItem 文件项
```



​        下面直接按照结构图构建具体代码:

```java
// 电脑,只需要管理任务栏和文件管理器即可。
public class Computer {

    private FileManager fileManager;
    private MissionBoard missionBoard;

    public Computer(FileManager fileManager, MissionBoard missionBoard) {
      this.fileManager = fileManager;
      this.missionBoard = missionBoard;
    }

    public void display(){
      Iterator fileManagerIterator = fileManager.createIterator();
      Iterator missionBoardIterator = missionBoard.createIterator();

      while (fileManagerIterator.hasNext()){
            Object next = fileManagerIterator.next();
            System.out.println(next);
      }

      while (missionBoardIterator.hasNext()){
            Object next = missionBoardIterator.next();
            System.out.println(next);
      }

    }
}

// 文件项
public class FileItem {

    private String fileName;

    private String editDate;

    private String ceateDate;

    private long size;

           // 省略部分内容
}

// 任务项
public class TaskItem {

    private String name;

    private int size;

    // 省略部分内容
}

// 迭代器规范接口
public interface Travelsable<E extends Object>{

    /**
   * 创建迭代器的方法
   * @return
   */
    Iterator<E> createIterator();
}

// 任务栏,管理任务项. 实现接口,支持迭代操作
public class MissionBoard implements Travelsable {

    private Stack<TaskItem> taskItems;

    public MissionBoard() {
      taskItems = new Stack<>();
      taskItems.push(new TaskItem("任务1", 10));
      taskItems.push(new TaskItem("任务2", 1230));
      taskItems.push(new TaskItem("任务3", 123));
      taskItems.push(new TaskItem("任务4", 414));
      taskItems.push(new TaskItem("任务5", 555));
    }

    @Override
    public Iterator createIterator() {
      return new TaskItemlIterator(taskItems);
    }

}

// 文件管理器,管理文件项,实现接口并且支持迭代操作
public class FileManager implements Travelsable{

    private FileItem[] fileItems;

    public FileManager() {
      this.fileItems = new FileItem;
      Random random = new Random(10000);
      for (int i = 0; i < fileItems.length; i++) {
            fileItems = new FileItem("文件"+i, random.nextInt(2000));
      }
    }

    @Override
    public Iterator createIterator() {
      return new FileIterator(fileItems);
    }

}

//文件迭代器
public class FileIterator implements Iterator{

    private FileItem[] fileItems;

    private int index;

    public FileIterator(FileItem[] fileItems) {
      this.fileItems = fileItems;
      this.index = 0;
    }

    @Override
    public boolean hasNext() {
      return index++ < fileItems.length - 1;
    }

    @Override
    public Object next() {
      return fileItems;
    }

    @Override
    public void remove(Object ele) {
      throw new UnsupportedOperationException("数组不支持当前操作");
    }
}

// 任务迭代器
public class TaskItemlIterator implements Iterator{

    private Stack<TaskItem> taskItems;

    public TaskItemlIterator(Stack<TaskItem> taskItems) {
      this.taskItems = taskItems;
    }

    @Override
    public boolean hasNext() {
      if(taskItems.isEmpty()){
            return false;
      }
      TaskItem peek = taskItems.peek();
      return peek != null;
    }

    @Override
    public Object next() {
      return taskItems.pop();
    }

    @Override
    public void remove(Object ele) {
      taskItems.remove(ele);
    }
}


```

以上就是迭代的大致实现案例代码,现代编程基本不会自己去设计迭代器,所以了解概念和知道样板代码即可。

# 总结:

​        迭代器在JAVA语言中基本已经实现到集合当中,当我们遍历集合的时候,其实就是在使用迭代器,迭代器通过**封装遍历**解耦了一堆对象的遍历和创建工作,将迭代的细节封装到一个黑盒当中,外部只需要调用接口就可以操作集合的数据。

52changew 发表于 2021-4-11 11:59

进一步了解下迭代器; 看看; 谢谢分享!!

tcclz 发表于 2021-4-11 12:56

学习了,谢谢分享

shaonianyou 发表于 2021-4-12 13:51

前排围观,学习一波

justice_hum 发表于 2021-4-13 18:13

谢谢楼主分享
页: [1]
查看完整版本: 浅谈设计模式 - 迭代器模式(十一)