关于java:我所知道设计模式之迭代器模式

4次阅读

共计 7161 个字符,预计需要花费 18 分钟才能阅读完成。

前言介绍


接下里介绍的是 Java 的设计模式之一:迭代器模式

咱们还是以一个问题进行开展,引入迭代器模式

编写程序展现一个学校院系构造:需要是这样,要在一个页面中展现出学校的院系组成,一个学校有多个学院,一个学院有多个系。如图

咱们之前用组合模式解决过这个问题,然而咱们当初要以遍历的角度去思考

怎么遍历他们?

一、传统形式解决问题

比如说目前

计算机学院采纳的是数组的形式存储、信息学院采纳汇合存储

那么咱们怎么去遍历他们?

解决方案:=> 迭代器模式

二、什么是迭代器模式

迭代器模式(Iterator Pattern)是罕用的设计模式,属于行为型模式

如果咱们的汇合元素是用 不同的形式实现 的,有数组,还有汇合类,或者还有其余形式,当客户端要遍历这些汇合元素的时候就要应用多种遍历形式,而且还会裸露元素的内部结构,能够思考应用迭代器模式解决。

迭代器模式,提供一种遍历汇合元素的对立接口,用统一的办法遍历汇合元素,不须要晓得汇合对象的底层示意,即:不裸露其外部的构造

迭代器原理类图剖析

Iterator:迭代器接口由零碎提供,含意 hasNext, next, remove

ConcreteIterator : 具体的迭代器类,治理迭代

Aggregate : 一个对立的聚合接口将客户端和具体聚合解耦

ConcreteAggreage : 具体的聚合持有对象汇合,并提供一个办法,返回一个迭代器,该迭代器能够正确遍历汇合

Client : 客户端,通过 Iterator 和 Aggregate 依赖子类

三、应用迭代器模式解决问题

依据咱们的思路,因为学院是蕴含系的,所以咱们须要先创立系这个类

// 系
class Department {

    private String name;// 名称
    private String desc;// 形容
    public Department(String name, String desc) {super();
        this.name = name;
        this.desc = desc;
    }

    public String getName() {return name;}

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

    public String getDesc() {return desc;}

    public void setDesc(String desc) {this.desc = desc;}
}

假如咱们计算机学院采纳的是数组的形式存储相干的计算机系

那么咱们依据思路创立计算机学院实现迭代器接口的实现类

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() {}
}

假如咱们信息学院采纳的是汇合的形式存储相干的信息系

那么咱们依据思路创立信息学院实现迭代器接口的实现类

class InfoColleageIterator implements Iterator {

    //  信息工程学院是以 List 形式寄存系
    List<Department> departmentList;

    // 索引
    int index = -1;

    public InfoColleageIterator(List<Department> departmentList) {this.departmentList = departmentList;}

    // 判断 list 中还有没有下一个元素
    @Override
    public boolean hasNext() {if (index >= departmentList.size() - 1) {return false;} else {
            index += 1;
            return true;
        }
    }

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

    // 空 实 现 remove
    @Override
    public void remove() {}
}

接下来咱们依据思路创立返回迭代器的接口

interface College {
    // 学院的名称
    public String getName();

    // 减少系的办法
    public void addDepartment(String name, String desc);

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

咱们依据思路首先创立于计算机学院对应的返回迭代器实现类

class ComputerCollege implements College {

    // 这里 Department 是以数组的形式寄存
    Department[] departments;

    // 保留以后数组的对象个数
    int numOfDepartment = 0;

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

    @Override
    public void addDepartment(String name, String desc) {
        // 依据传入的信息创立系
        Department department = new Department(name, desc);
        departments[numOfDepartment] = department;
        numOfDepartment += 1;
    }

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

咱们再依据思路创立于信息学院对应的返回迭代器实现类

class InfoCollege implements College {

    // 汇合的形式存储
    List<Department> departmentList;

    @Override
    public String getName() {return "信息工程学院";}
    @Override
    public void addDepartment(String name, String desc) {Department department = new Department(name, desc);
        departmentList.add(department);
    }
    @Override
    public Iterator createIterator() {return new InfoColleageIterator(departmentList);
    }
}

计算机学院应用数组的形式存储、信息学院应用汇合的形式存储

这时咱们创立一个输入类,通过迭代器的形式输入所有学院

class OutPutImpl {

    // 学院汇合
    List<College> collegeList;

    public OutPutImpl(List<College> collegeList) {this.collegeList = collegeList;}

    // 遍历所有学院, 而后调用 printDepartment  输入各个学院的系
    public void printCollege() {
        // 从 collegeList 取出所有学院, Java 中的 List 曾经实现 Iterator
        Iterator<College> iterator = collegeList.iterator();
        while (iterator.hasNext()) {
            // 取出一个学院
            College college = iterator.next();
            System.out.println("===" + college.getName() + "=====");
            printDepartment(college.createIterator()); // 失去对应迭代器
        }
    }

    // 输入 学院输入 系
    public void printDepartment(Iterator iterator) {while (iterator.hasNext()) {Department d = (Department) iterator.next();
            System.out.println(d.getName());
        }
    }
}

接下来咱们应用 demo 一起领会看看,是怎么将两组不同存储形式遍历的

public static void main(String[] args) {

    // 创立存储迭代类
    List<College> collegeList = new ArrayList<College>();

    // 创立返回对应计算机学院迭代器
    ComputerCollege computerCollege = new ComputerCollege();
    // 创立存储计算机学院的里的系
    computerCollege.departments = new Department[5];
    // 将计算机学院里的系,存储到迭代器里
    computerCollege.addDepartment("Java 业余", "Java 业余");
    computerCollege.addDepartment("PHP 业余", "PHP 业余");
    computerCollege.addDepartment("大数据业余", "大数据业余");

    // 创立返回对应信息学院对应迭代器
    InfoCollege infoCollege = new InfoCollege();
    // 创立存储计算机学院的里的系
    infoCollege.departmentList = new ArrayList<Department>();
    // 将信息学院里的系,存储到迭代器里
    infoCollege.addDepartment("信息安全业余", "信息安全业余");
    infoCollege.addDepartment("网络安全业余", "网络安全业余");
    infoCollege.addDepartment("服务器平安业余", "服务器平安业余");

    // 将两个学院的迭代器增加进汇合中
    collegeList.add(computerCollege);
    collegeList.add(infoCollege);

    // 将汇合交给帮忙输入类进行输入
    OutPutImpl outPutImpl = new OutPutImpl(collegeList);
    outPutImpl.printCollege();}

运行后果如下:=== 计算机学院 =====
Java 业余
PHP 业余
大数据业余
=== 信息工程学院 =====
信息安全业余
网络安全业余
服务器平安业余

四、迭代器在源码中的应用

咱们先应用一个示例,来看看 ArrayList 的应用与输入

public static void main(String[] args) {List<String> list = new ArrayList<>();
    list.add("Jack");

    Iterator<String> integer = list.iterator();
    while(integer.hasNext()){System.out.println(integer.next());
    }
}

运行后果如下:Jack

诶,为什么 ArrayList 能够应用 Iterator 迭代器呢?

咱们一起进 ArrayList 的源码里去看看,发现它实现了 List 汇合的接口

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{//.... 省略关键性的代码}

那么 List 汇合这个接口做了什么事件?咱们也进去看看

public interface List<E> extends Collection<E> {int size();

    boolean isEmpty();

    boolean contains(Object o);

    Iterator<E> iterator();

    Object[] toArray();
    
    // 省略其余关键性代码.....
}

诶,咱们发现 List 汇合里有一个 iterator 办法

那么 ArrayList 有没有对着这个办法实现呢?咱们一起进去找找看看

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{public Iterator<E> iterator() {return new Itr();
    }
    private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        Itr() {}

        public boolean hasNext() {return cursor != size;}

        @SuppressWarnings("unchecked")
        public E next() {checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        public void remove() {if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {throw new ConcurrentModificationException();
            }
        }

        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {return;}
            final Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length) {throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {consumer.accept((E) elementData[i++]);
            }
            // update once at end of iteration to reduce heap write traffic
            cursor = i;
            lastRet = i - 1;
            checkForComodification();}

        final void checkForComodification() {if (modCount != expectedModCount)
                throw new ConcurrentModificationException();}
    }
    
    // 省略其余关键性代码....
}

咱们这样就发现了,一下就思路就苏醒了,请看类图剖析

Itr 是 ArrayList 的一个外部类,自身应用 ArrayList 里的 elementData

因而与原先迭代模式不一样,它是间接应用

五、迭代器模式的注意事项和细节


Ø 长处

提供一个对立的办法遍历对象,客户不必再思考聚合的类型,应用一种办法就能够遍历对象了。

暗藏了聚合的内部结构,客户端要遍历聚合的时候只能取到迭代器,而不会晓得聚合的具体组成。

提供了一种设计思维,就是一个类应该只有一个引起变动的起因(叫做繁多责任准则)。

在聚合类中,咱们把迭代器离开,就是要把治理对象汇合和遍历对象汇合的责任离开,这样一来汇合扭转的话,只影响到聚合对象。

而如果遍历形式扭转的话,只影响到了迭代器。

当要展现一组类似对象,或者遍历一组雷同对象时应用, 适宜应用迭代器模式

Ø 毛病

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

参考资料


尚硅谷:设计模式(韩顺平老师):迭代器模式

Refactoring.Guru:《深刻设计模式》

正文完
 0