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

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循环的原理。上述方式除了遍历方式不一致外,丙还得知道甲乙两人的内部存储细节。然后他们讨论,为了统一遍历方式,以及不暴露自身内部存储细节,对数据存储进行了改进。
好了,经过讨论,通用存储模式类图如下:
在这里插入图片描述
方法描述:addElement和removeElement方法用以增加和删除元素,next()、previous()、isFirst()等方法用以遍历元素。
那么上述方法存在什么问题呢?
1、该类既要负责数据存储,又要负责遍历数据,违反设计模式单一职责原则。
2、如果将该类声明为一个接口,交给子类去实现,那么这个接口必定包含大量方法,不利于子类去实现,违反接口隔离原则。
3、如果将遍历交给子类负责,子类就肯定要访问AbstractStoreElement中存储的元素,就必须暴露AbstractStoreElement的内部存储细节,不然子类无法进行遍历,又破坏了AbstractStoreElement的封装性。
于是甲乙丙三人将遍历元素的方法提取出来,将数据存储和数据遍历分离开来。无须暴露AbstractStoreElement的内部存储细节即可完成对它的遍历。这就是迭代器模式的意图所在。
最后经过改进得到的类图如下:
在这里插入图片描述
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源码中是如何应用的。
本文若有不足之处,还请大家多多指正。如果这篇文章帮助到您,请您点赞支持。若有疑问,请小伙伴们私信我,或者评论区留言。谢谢大家。

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值