设计模式之迭代器模式

迭代器模式提供了一种访问聚合对象如集合的元素而不暴露其内部结构的方式。通过迭代器,外部访问更加简单,同时保持集合内部表示的封装。Java集合框架中的Iterator是迭代器模式的实现,每个集合内部都有专属的迭代器,实现了遍历的统一接口,但内部实现根据集合类型不同。这种模式符合单一职责原则,简化了聚合对象的职责。
摘要由CSDN通过智能技术生成


1.定义

迭代器模式,属于行为型模式。其目的是提供一种顺序访问访问聚合对象(集合)中的各种元素,而又不暴露该对象的内部表示。

迭代可以理解为就是对集合对象内部元素的遍历访问,一般情况下可以通过直接访问这个对象(集合)或者获取对象元素进行遍历,这是传统的做法。迭代器提供了一种更优雅、更灵活的遍历方式,使得外部访问对象(集合)的元素更为简单,单一。

提到迭代器,一般会想起Java集合框架中的迭代器Iterator,是的,他们的迭代器就是迭代器模式的实现,其内部原理很简单,每个集合内部都会以内部类的方式维护一个专属的迭代器,迭代器是可以访问集合对象内部的元素的,根据集合的不同特性对应的迭代器实现也不同,迭代器的职责范围仅仅属于当前的集合,然后对所有的迭代器通过接口的方式向外暴露,供外部调用。

譬如以下代码:

        List<String> arrayList = new ArrayList<>();
        Iterator<String> it1 = arrayList.iterator();

        LinkedList<Object> linkedList = new LinkedList<>();
        Iterator<Object> it2 = linkedList.iterator();

虽然ArrayList和LinkedList都是返回了迭代器,但是迭代器是集合内部的私有对象,所谓私有。两层含义:其一迭代器在集合内部被private修饰 其二迭代器是为当前集合“定制”,只适用于当前数据结构,比如以上的两个迭代器,ArrayList迭代器是基于数组的方式操作元素,而LinkedList迭代器是基于链表的方式操作元素,在外部使用来看,他们似乎并无区别。而从这里也能看出来,迭代器为所有的对象集合统一了访问的方式,但他们的内部实现因集合而异,亦或者可以说是将遍历访问行为从集合中独立出来,更加符合单一职责原则。

迭代器实现可谓相当多
在这里插入图片描述
简单贴两个看下

ArrayList迭代器实现(数组):
在这里插入图片描述
LinkedList迭代器实现(链表):

在这里插入图片描述
通过以上分析,不难发现,迭代器模式总体上就两个角色,对象聚合类和迭代器,细分的话,加上抽象层就是四个

  • Aggregate(抽象聚合类):它用于储存和管理元素对象,包含一个方法,返回迭代器实例
  • ConcreteAggregate(聚合聚合类):实现了抽象聚合类的方法,返回具体的实例
  • Iterator(抽象迭代器):包含了访问聚合对象内部元素的方法,比如是否有下一个元素hasNext,取下一个next,或者可以定义一个previous,向前遍历等等
  • ConcreteIterator(具体迭代器):对应具体的聚合对象的迭代器实现,根据实际需求结合聚合对象特征实现

UML:
在这里插入图片描述
图片来源:百度图库

2.示例

如果上边您已经完全理解,接下来的简单看看就好,这里给出一个简单实现,供参考
以一个简单Person类,来实现迭代器,首先定义Person抽象层,提供基本的对象访问方法,如add/remove等,其中最重要的是定义一个用于返回迭代器的方法getIterator(),具体实现中应返回对象专属的迭代器实例

/**
 * @description: 聚合对象抽象
 * @version: 1.0
 */
public interface Person {

    void addAll(List<Object> objects);
    
    void add(Object o);

    void remove(Object o);

    Iterator getIterator();
}

聚合对象实现,这里使用一个list作为存储元素的容器,这个list其实就是迭代器操作的对象

/**
 * @description: 聚合对象实现
 * @version: 1.0
 */
public class Student implements Person{

    private List<Object> elements = new ArrayList<>();

    @Override
    public void addAll(List<Object> objects) {
        elements.addAll(objects);
    }

    @Override
    public void add(Object o) {
        elements.add(o);
    }

    @Override
    public void remove(Object o) {
        elements.remove(o);
    }

    @Override
    public Iterator getIterator() {
        return new PersonIterator(elements);
    }
}

迭代器的抽象层,这里简单定义两个方法 一个hasNext 一个 next方法,用于判断是否还有元素以及指针向下偏移获取元素,(这里需要注意的是,next每次调用,偏移+1)

/**
 * @description: 迭代器抽象
 * @version: 1.0
 */
public interface Iterator<E> {

    boolean hasNext();

    E next();
}

迭代器的实现,迭代器初始化时必须持有需要访问的元素

/**
 * @description: 迭代器实现
 * @version: 1.0
 */
public class PersonIterator implements Iterator{
    private List<Object> elements = null;

    private int index = -1;

    public PersonIterator(List<Object> elements) {
        this.elements = elements;
    }

    @Override
    public boolean hasNext() {
        return index + 1 < elements.size();
    }

    @Override
    public Object next() {
        return hasNext() ? elements.get(++index) : null;
    }
}

测试:

/**
 * @description: test
 * @version: 1.0
 */
public class Test {
    public static void main(String[] args) {
        String[] persons = {"张三","李四","王五","赵大娘","王大爷","马冬梅"};
        Person stu = new Student();
        stu.addAll(Arrays.asList(persons));


        for (Iterator iterator = stu.getIterator();iterator.hasNext();){
            Object next = iterator.next();
            System.out.println(next);
        }
    }
}

input:

张三
李四
王五
赵大娘
王大爷
马冬梅
3.总结

迭代器的最重要的优点就是使得聚合对象的职责变得简单,聚合对象不需要再提供遍历自身的方法,取而代之的是迭代器去完成,并且可以提供一种隐藏内部数据、约束元素访问方式的机制,对于客户端透明,扩展方便,符合开闭原则和单一职责原则。缺点自然就是多了迭代器类的设计,如果对象过多,那可能就需要对迭代器进行一些列更高抽象的设计,这会增加一定的设计复杂性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值