设计模式 | 迭代器模式(详解)

迭代器模式

前言
很早之前,我们的电视调节频道是需要用电视上的按钮去控制的,那时并没有遥控器,如果我们想要调台,只能一次又一次的拧按钮。

设计模式 | 迭代器模式(详解)_第1张图片
越来越高级的电视机相继出现,现在的电话机,我们有了电视遥控器,我们使用电视遥控器来调台,这个时候,无需直接操作电视。
设计模式 | 迭代器模式(详解)_第2张图片设计模式 | 迭代器模式(详解)_第3张图片
我们可以将电视机看成一个存储电视频道的集合对象,通过遥控器可以对电视机中的电视频道集合进行操作,如返回上一个频道、跳转到下一个频道或者跳转至指定的频道。遥控器为我们操作电视频道带来很大的方便,用户并不需要知道这些频道到底如何存储在电视机中。

具体案例:
编写程序展示一个学校院系结构:需求是这样,要在一个页面中展示出学校的院系 组成, 一个学校有多个学院,一个学院有多个系
分析:

每一个学院都有添加系的功能,如果我们将遍历的方法hasNext() next()等写入。这将导致聚合类的职责过重,它既负责存储和管理数据,又负责遍历数据,违反了“单一职责原则”,由于聚合类非常庞大,实现代码过长,还将给测试和维护增加难度。

那么这个时候,我们也许会这样想,因为有多个学院,我们不妨将学院封装为接口,但是在这个接口中充斥着大量方法,不利于子类实现,违反了“接口隔离原则”。

解决方案:

解决方案之一就是将聚合类中负责遍历数据的方法提取出来,封装到专门的类中,实现数据存储和数据遍历分离,无须暴露聚合类的内部属性即可对其进行操作,而这正是迭代器模式的意图所在。

基本介绍
  1. 迭代器模式(Iterator Pattern)是常用的设计模式,属于行为型模式
  2. 如果我们的集合元素是用不同的方式实现的,有数组,还有java的集合类,
    或者还有其他方式,当客户端要遍历这些集合元素的时候就要使用多种遍历
    方式,而且还会暴露元素的内部结构,可以考虑使用迭代器模式解决。
  3. 迭代器模式,提供一种遍历集合元素的统一接口,用一致的方法遍历集合元素,
    不需要知道集合对象的底层表示,即:不暴露其内部的结构。
原理类图:

设计模式 | 迭代器模式(详解)_第4张图片

角色分析:
  1. Iterator (抽象迭代器): 迭代器接口,是系统提供,含义 hasNext, next, remove
  2. ConcreteIterator (具体迭代器): 具体的迭代器类,管理迭代 在具体迭代器中通过游标来记录在聚合对象中所处的当前位置,在具体实现时,游标通常是一个表示位置的非负整数。
  3. Aggregate (抽象聚合类):一个统一的聚合接口, 将客户端和具体聚合解耦
  4. ConcreteAggreage (具体聚合类): 具体的聚合持有对象集合, 并提供一个方法,返回一个
代码实例:

聚合类:

学院接口:

/**
 * 学院
 *
 * @author 孙一鸣 on 2020/2/17
 */
public interface College {

    public String getName();
    //增加系的方法
    public void addDepartment (String name,String des);

    //换回一个迭代器,遍历
    public Iterator createIterator();

}

计算机学院:


/**
 * 计算机学院
 *
 * @author 孙一鸣 on 2020/2/17
 */
public class ComputerCollege implements College
{
    Department[] departments;
    int numOfDepartment = 0;//保存当前数组对象个数

    public ComputerCollege() {
        departments = new Department[5];//计算机学院有5个系
        addDepartment("Java","JAVA牛逼");
        addDepartment("Php","经典");
        addDepartment("C#","还好");
        addDepartment("Python","智能");
        addDepartment("GO","牛");

    }

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

    //给计算机学院添加系
    @Override
    public void addDepartment(String name,String des) {
        Department department = new Department(name,des);
        departments[numOfDepartment] = department;
        numOfDepartment += 1;
    }

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

信息学院


/**
 * 信息学院
 *
 * @author 孙一鸣 on 2020/2/17
 */
public class InfoCollege implements College
{
    List<Department> departments;
   // int numOfDepartment = 0;//保存当前数组对象个数

    public InfoCollege() {
        departments = new ArrayList<Department>();
        //计算机学院有5个系
        addDepartment("信息安全","JAVA牛逼");
        addDepartment("网络安全","经典");
        addDepartment("服务器安全","还好");
        addDepartment("数据库安全","智能");
    }

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

    //给计算机学院添加系
    @Override
    public void addDepartment(String name,String des) {
        Department department = new Department(name,des);
       departments.add(department);
        //numOfDepartment += 1;
    }

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

学院下面的系:


/**
 * 系
 *学校 --学院 -- 系
 * @author 孙一鸣 on 2020/2/17
 */
public class Department {
     private  String name;
     private  String des;

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDes() {
        return des;
    }

    public void setDes(String des) {
        this.des = des;
    }
}

迭代器类:
计算机学院迭代器


/**
 * @author 孙一鸣 on 2020/2/17
 * ComputerCollegeIterator: 计算机学院迭代器,
 * 遍历计算机学院下的系
 */
public class ComputerCollegeIterator implements Iterator {

    /*
    * 这里需要知道 Department 以怎样的方式存放
    *
    * */

    Department[] departments;
    int position = 0;//遍历的位置

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

    @Override
    public boolean hasNext() {
        if (position >= departments.length || departments[position] ==null)
        {
            return false;
        }else {
            return  true;
        }
    }

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

    @Override
    public void remove() {

    }
}

信息学院迭代器:


/**
 * @author 孙一鸣 on 2020/2/17
 * ComputerCollegeIterator: 信息学院迭代器,
 * 遍历信息学院下的系
 */
public class InfoCollegeIterator implements Iterator {

    /*
    * 这里需要知道 Department 以怎样的方式存放
    *
    * */

    List<Department> departments;
    int position = -1;//索引

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

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

    @Override
    public Object next() {

        return departments.get(position);
    }

    @Override
    public void remove() {

    }
}

输出信息类:


/**
 * @author 孙一鸣 on 2020/2/17
 * 输出信息类
 */
public class OutPutClass {
    List<College> colleges;

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

    //遍历单个学院取出系
    public void printDepartment(Iterator iterator) {
        while (iterator.hasNext()) {
            Department department = (Department) iterator.next();
            System.out.println("department.getName() = " + department.getName());
        }
    }

    //遍历学院集合 输出所有学院
    public void printCollege() {
        //此时遍历不用传入 迭代器
        //学院使用List集合 已经实现Iterator
        Iterator<College> iterator = colleges.iterator();
        while(iterator.hasNext()){
            //取出一个学院
            College college = iterator.next();
            System.out.println("========="+college.getName()+"====");
            printDepartment(college.createIterator());
        }
    }
}

测试类:


/**
 * @author 孙一鸣 on 2020/2/17
 */
public class Client {
    public static void main(String[] args) {
        List<College> colleges = new ArrayList<College>();
        College computerCollege = new ComputerCollege();
        College infocollege = new InfoCollege();
        colleges.add(computerCollege);
        colleges.add(infocollege);

        OutPutClass outPutClass = new OutPutClass(colleges);
        outPutClass.printCollege();
    }
}

结果截图:

设计模式 | 迭代器模式(详解)_第5张图片

代码分析:

如果需要增加一个新的具体聚合类,只需增加一个新的聚合子类和一个新的具体迭代器类即可,原有类库代码无须修改,符合“开闭原则”;

如果需要为聚合类更换一个迭代器,只需要增加一个新的具体迭代器类作为抽象迭代器类的子类,重新实现遍历方法,原有迭代器代码无须修改,也符合“开闭原则”;

但是如果要在迭代器中增加新的方法,则需要修改抽象迭代器源代码,这将违背“开闭原则”。

迭代器模式在JDK-ArrayList集合应用的源码分析

设计模式 | 迭代器模式(详解)_第6张图片
角色分析说明

  • 内部类Itr 充当具体实现迭代器Iterator 的类, 作为ArrayList 内部类
  • List 就是充当了聚合接口,含有一个iterator() 方法,返回一个迭代器对象
  • ArrayList 是实现聚合接口List 的子类,实现了iterator()
  • Iterator 接口系统提供
  • 迭代器模式解决了 不同集合(ArrayList ,LinkedList) 统一遍历问题

优点

  1. 提供一个统一的方法遍历对象,客户不用再考虑聚合的类型,使用一种方法就可以遍历对象了。
  2. 隐藏了聚合的内部结构,客户端要遍历聚合的时候只能取到迭代器,而不会知道聚合的具体组成。
  3. 提供了一种设计思想,就是一个类应该只有一个引起变化的原因(叫做单一责任
    原则)。在聚合类中,我们把迭代器分开,就是要把管理对象集合和遍历对象集
    合的责任分开,这样一来集合改变的话,只影响到聚合对象。而如果遍历方式改变的话,只影响到了迭代器。
  4. 当要展示一组相似对象,或者遍历一组相同对象时使用, 适合使用迭代器模式

缺点
每个聚合对象都要一个迭代器,会生成多个迭代器不好管理类

你可能感兴趣的:(Java设计模式详细学习专栏)