超详细-设计模式之迭代器模式

Hello,大家好:
今天我们来聊一下设计模式中迭代器模式。
背景:
甲、乙、丙三人合作开发一套人员管理系统,甲在编程中习惯使用数组存储元素,乙喜欢编程中习惯使用List等集合存储元素,丙在项目开发中刚好需要遍历甲、乙存储的元素。无奈,丙只能写两套不同的遍历方法,上述场景用代码描述为:

 StudentContainer studentContainer = new StudentContainer();
 List<Student> students = studentContainer.getStudents();
 for (int i = 0; i < students.size(); i++) {
     
     System.out.println(students.get(i).getStudentNum());
 }
 TeacherContainer teacherContainer = new TeacherContainer();
 Teacher[] teachers = teacherContainer.getTeachers();
 for (int i = 0; i < teachers.length; i++) {
     
     System.out.println(teachers[i]);
 }

注意,可能小伙伴们会说可以使用增强for循环呀,其实那也是JDK对迭代器模式的一种实现,在后续的博客中我们将从JDK字节码层面来看看增强for循环的原理。上述方式除了遍历方式不一致外,丙还得知道甲乙两人的内部存储细节。然后他们讨论,为了统一遍历方式,以及不暴露自身内部存储细节,对数据存储进行了改进。
好了,经过讨论,通用存储模式类图如下:
超详细-设计模式之迭代器模式_第1张图片
方法描述:addElement和removeElement方法用以增加和删除元素,next()、previous()、isFirst()等方法用以遍历元素。
那么上述方法存在什么问题呢?
1、该类既要负责数据存储,又要负责遍历数据,违反设计模式单一职责原则。
2、如果将该类声明为一个接口,交给子类去实现,那么这个接口必定包含大量方法,不利于子类去实现,违反接口隔离原则。
3、如果将遍历交给子类负责,子类就肯定要访问AbstractStoreElement中存储的元素,就必须暴露AbstractStoreElement的内部存储细节,不然子类无法进行遍历,又破坏了AbstractStoreElement的封装性。
于是甲乙丙三人将遍历元素的方法提取出来,将数据存储和数据遍历分离开来。无须暴露AbstractStoreElement的内部存储细节即可完成对它的遍历。这就是迭代器模式的意图所在。
最后经过改进得到的类图如下:
超详细-设计模式之迭代器模式_第2张图片
AbstractStoreElement(抽象存储类):用于存储和管理元素对象的抽象类,具体如何管理交由子类去实现,声明createIterator方法来创建一个迭代器。
ConcreteStorefElement(具体存储类):继承AbstractStoreElement,实现createIterator()方法,返回一个与该具体存储类对应的具体迭代器。
Iterator(抽象迭代器):定义访问和遍历元素的接口,声明用于遍历的方法。
ConcreteIterator(具体迭代器):它实现了抽象迭代器中的所有方法,完成对存储类中的元素的遍历操作。具体迭代器中通过游标来记录在聚合对象中所处的当前位置。
附录完整代码:
AbstractStoreElement:

public abstract class AbstractStoreElement {
     
    // 声明创建迭代器对象的抽象工厂方法
    public abstract AbstractIterator createIterator();
}

ConcreteStoreElement:

public class ConcreteStoreElement extends AbstractStoreElement {
     
    protected List<Student> students = new ArrayList<Student>();

    public ConcreteStoreElement(List<Student> students) {
     
        this.students = students;
    }

    public void addObject(Student obj) {
     
        this.students.add(obj);
    }

    public void removeObject(Object obj) {
     
        this.students.remove(obj);
    }

    public List<Student> getObjects() {
     
        return this.students;
    }
    // 实现创建迭代器对象的具体工厂方法
    public AbstractIterator createIterator() {
     
        return new ConcreteIterator(this);
    }
}

AbstractIterator:

public interface AbstractIterator {
     
    public void next(); // 移至下一个元素

    public boolean isLast(); // 判断是否为最后一个元素

    public void previous(); // 移至上一个元素

    public boolean isFirst(); // 判断是否为第一个元素

    public Object getNextItem(); // 获取下一个元素

    public Object getPreviousItem(); // 获取上一个元素
}

ConcreteIterator:

public class ConcreteIterator implements AbstractIterator{
     
    private List<Student> students;
    private int cursor1; // 定义一个游标,用于记录正向遍历的位置
    private int cursor2; // 定义一个游标,用于记录逆向遍历的位置
   
    public ConcreteIterator(ConcreteStoreElement list) {
     
        this.students = list.getObjects(); // 获取集合对象
        cursor1 = 0; // 设置正向遍历游标的初始值
        cursor2 = students.size() - 1; // 设置逆向遍历游标的初始值
    }

    public void next() {
     
        if (cursor1 < students.size()) {
     
            cursor1++;
        }
    }

    public boolean isLast() {
     
        return (cursor1 == students.size());
    }

    public void previous() {
     
        if (cursor2 > -1) {
     
            cursor2--;
        }
    }

    public boolean isFirst() {
     
        return (cursor2 == -1);
    }

    public Object getNextItem() {
     
        return students.get(cursor1);
    }

    public Object getPreviousItem() {
     
        return students.get(cursor2);
    }

}

好,迭代器的原理就讲到这儿啦,下一篇我们来解析一下迭代器在jdk源码中是如何应用的。
本文若有不足之处,还请大家多多指正。若有疑问,请小伙伴们私信我,或者评论区留言。
此外推荐一下尚硅谷的Java基础阶段学习资料包括多线程、数据、开发工具等等,视频+源码+笔记。资料详情如下:
超详细-设计模式之迭代器模式_第3张图片

非常好的Java学习资料,请大家关注《炫酷的Java》公众号,输入javase,即可下载,谢谢大家。

超详细-设计模式之迭代器模式_第4张图片

你可能感兴趣的:(设计模式,java)