设计模式之迭代器模式

迭代器模式又称游标模式,属于行为型模式;指提供一些方法来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表象。迭代器模式是通过将聚合对象的遍历行为分离出来,抽象成迭代器类来实现的,其目的是在不暴露聚合对象的内部结构的情况下,让外部代码透明地访问聚合的内部数据。

迭代器模式是最常见的几个设计模式之一,也是被广泛地应用到Java语言API中的几个设计模式之一。在Java语言的集合(Collection)框架中,广泛使用迭代器来遍历聚集的元素。

迭代器模式的UML类图如下:

从上图可知,迭代器模式涉及到抽象聚合角色、具体聚合角色、抽象迭代器角色、具体迭代器角色等四种角色:

  1. 抽象聚合(Aggregate)角色:定义存储、添加、删除聚合对象以及创建迭代器对象的接口。
  2. 具体聚合(ConcreteAggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例。
  3. 抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、first()、next() 等方法。
  4. 具体迭代器(Concretelterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。

迭代器分为主动迭代被动迭代,主要是相对于客户端而言的。如果客户端控制迭代的进程,那么这样的迭代就是主动迭代,相反就是被动迭代。使用主动迭代的客户端会明显调用迭代器的next()等迭代方法,在遍历的过程中向前迭代,而客户端在使用被动迭代时,明显不会调用迭代方法,而是由迭代器自行推进遍历过程。而我们在开发过程中大部分都是使用的主动迭代。

学校院系例子

在一个大学里,由很多个学院组成,每个学院下又有很多系。如果要知道这个大学由多少个学院,一个学院由多少个专业,就可以使用迭代器模式。

该系统的UML类图如下:

抽象聚合角色:

package com.charon.iterator;

import java.util.Iterator;

/**
 * @className: College
 * @description: 学院
 * @author: charon
 * @create: 2022-03-27 14:52
 */
public interface College {

    /**
     * 获取学院的名称
     * @return
     */
    String getName();

    /**
     * 添加学院
     * @param name 名称
     * @param desc 描述
     */
    void addDepartment(String name,String desc);

    /**
     * 返回一个迭代器对象,用于遍历
     * @return
     */
    Iterator createIterator();
}

具体聚合角色:

package com.charon.iterator;

import java.util.Iterator;

/**
 * @className: ComputerCollege
 * @description: 计算机学院
 * @author: charon
 * @create: 2022-03-27 14:56
 */
public class ComputerCollege implements College{

    Department[] departments;

    /**
     * 下面系的个数
     */
    int departmentNum;

    public ComputerCollege() {
        departments = new Department[3];
        addDepartment("计算机科学与技术","计算机科学与技术");
        addDepartment("电子科学与技术","电子科学与技术");
        addDepartment("信息与通信工程","信息与通信工程");
    }

    @Override
    public String getName() {
        return "计算机学院";
    }

    @Override
    public void addDepartment(String name, String desc) {
        Department department = new Department(name, desc);
        departments[departmentNum] = department;
        departmentNum++;
    }

    @Override
    public Iterator createIterator() {
        return new ComputerCollegeIterator(departments);
    }
}


package com.charon.iterator;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @className: InfoCollege
 * @description: 信息工程学院
 * @author: charon
 * @create: 2022-03-27 15:11
 */
public class InfoCollege implements College{

    List<Department> departments;

    public InfoCollege() {
        departments = new ArrayList<>(5);
        addDepartment("电气工程及自动化","电气工程及自动化");
        addDepartment("电子信息工程","电子信息工程");
        addDepartment("测控技术与仪器","测控技术与仪器");
        addDepartment("电子科学与技术","电子科学与技术");
        addDepartment("物联网工程","物联网工程");
        addDepartment("通信工程","通信工程");
    }

    @Override
    public String getName() {
        return "信息工程学院";
    }

    @Override
    public void addDepartment(String name, String desc) {
        Department department = new Department(name, desc);
        departments.add(department);
    }

    @Override
    public Iterator createIterator() {
        return new InfoCollegeIterator(departments);
    }
}

具体迭代器角色:

package com.charon.iterator;

import java.util.Iterator;

/**
 * @className: ComputerCollegeIterator
 * @description:
 * @author: charon
 * @create: 2022-03-27 15:05
 */
public class ComputerCollegeIterator implements Iterator {

    /**
     * 存放专业的容器
     */
    Department[] departments;

    /**
     * 游标,用于记录遍历的位置
     */
    int cursor;

    public ComputerCollegeIterator(Department[] departments) {
        this.departments = departments;
    }

    @Override
    public boolean hasNext() {
        return cursor < departments.length && departments[cursor] != null;
    }

    @Override
    public Object next() {
        Department department = departments[cursor];
        cursor++;
        return department;
    }
}


package com.charon.iterator;

import java.util.Iterator;
import java.util.List;

/**
 * @className: InfoCollegeIterator
 * @description:
 * @author: charon
 * @create: 2022-03-27 15:16
 */
public class InfoCollegeIterator implements Iterator {

    List<Department> departments;
    /**
     * 数组下标
     */
    int index;

    public InfoCollegeIterator(List<Department> departments) {
        this.departments = departments;
    }

    @Override
    public boolean hasNext() {
        if (index >= departments.size() -1){
            return false;
        }
        index++;
        return true;
    }

    @Override
    public Object next() {
        return departments.get(index);
    }
}

其他:

package com.charon.iterator;

/**
 * @className: Department
 * @description: 系
 * @author: charon
 * @create: 2022-03-27 14:58
 */
public class Department {

    private String name;

    private String desc;

    public Department(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }

    /**
     * Gets the value of name
     *
     * @return the value of name
     */
    public String getName() {
        return name;
    }
}


package com.charon.iterator;

import java.util.Iterator;
import java.util.List;

/**
 * @className: OutputImpl
 * @description:
 * @author: charon
 * @create: 2022-03-27 15:19
 */
public class OutputImpl {

    List<College> colleges;

    public OutputImpl(List<College> colleges) {
        this.colleges = colleges;
    }

    /**
     * 遍历所有的学院,并依次输出
     */
    public void printCollege(){
        Iterator<College> iterator = colleges.iterator();
        while (iterator.hasNext()){
            // 取出一个学院
            College college = iterator.next();
            System.out.println("学院:" + college.getName());
            printDepartment(college.createIterator());
        }
    }

    /**
     * 输出专业
     * @param iterator
     */
    private void printDepartment(Iterator iterator) {
        while (iterator.hasNext()){
            Department department = (Department) iterator.next();
            System.out.println("该学院下的专业有:" + department.getName());
        }
    }
}

测试:

package com.charon.iterator;

import java.util.ArrayList;
import java.util.List;

/**
 * @className: Client
 * @description:
 * @author: charon
 * @create: 2022-03-27 15:27
 */
public class Client {

    public static void main(String[] args) {
        // 创建学院
        List<College> colleges = new ArrayList<>(2);
        
        colleges.add(new ComputerCollege());
        colleges.add(new InfoCollege());

        OutputImpl output = new OutputImpl(colleges);
        output.printCollege();
    }
}

打印:
    学院:计算机学院
    该学院下的专业有:计算机科学与技术
    该学院下的专业有:电子科学与技术
    该学院下的专业有:信息与通信工程
    学院:信息工程学院
    该学院下的专业有:电子信息工程
    该学院下的专业有:测控技术与仪器
    该学院下的专业有:电子科学与技术
    该学院下的专业有:物联网工程
    该学院下的专业有:通信工程

迭代器模式的优点如下:

  1. 访问一个聚合对象的内容而无须暴露它的内部表示。
  2. 遍历任务交由迭代器完成,这简化了聚合类。
  3. 它支持以不同方式遍历一个聚合,甚至可以自定义迭代器的子类以支持新的遍历。
  4. 增加新的聚合类和迭代器类都很方便,无须修改原有代码。
  5. 封装性良好,为遍历不同的聚合结构提供一个统一的接口。

迭代器模式的缺点如下:

  1. 增加了类的个数,这在一定程度上增加了系统的复杂性

迭代器模式的应用场景

由于聚合与迭代器的关系非常密切,所以大多数语言在实现聚合类时都提供了迭代器类,因此大数情况下使用语言中已有的聚合类的迭代器就已经够了。

迭代器模式通常在以下几种情况使用。

  1. 当需要为聚合对象提供多种遍历方式时。
  2. 当需要为遍历不同的聚合结构提供一个统一的接口时。
  3. 当访问一个聚合对象的内容而无须暴露其内部细节的表示时。
posted @ 2022-03-27 15:47  pluto_charon  阅读(448)  评论(0编辑  收藏  举报