2

一、迭代器模式介绍

1. 解决的问题

主要解决遍历整个集合对象的问题。

2. 定义

迭代器模式是一种行为设计模式,能在不暴露底层表现形式(列表、栈和树等)的情况下遍历集合中所有的元素。

3. 应用场景

  • 当集合背后为复杂的数据结构,且希望对客户端隐藏其复杂性时(处于使用便利性或安全性考虑),可以使用迭代器模式。
  • 减少程序中重复的遍历代码,可以使用迭代器模式。
  • 希望代码能够遍历不同的甚至无法预知的数据结构,可以使用迭代器模式。

二、迭代器模式优缺点

1. 优点

  • 单一职责原则:通过将体积庞大的遍历算法代码抽取为独立的类,可以对客户端代码和集合进行整理。
  • 开闭原则:可实现新型的集合和迭代器并将其传递给现有代码,无需修改现有代码。
  • 可以并行遍历同一集合,因为每个迭代器对象都包含其自身的遍历状态;同时,也可以暂停遍历并在需要时继续。

2. 缺点

  • 如果程序只与简单的集合进行交互,使用迭代器模式可能会矫枉过正。
  • 对于某些特殊集合,使用迭代器可能比直接遍历的效率低。

三、迭代器模式应用实例: 你有多少 QQ 好友呢?

1. 实例场景

微信的崛起,就是QQ的落寞,现在用QQ的应该越来越少了,但QQ很多功能还是挺好用的,比如好友的分组功能,这样就完全可以将从学校、网络上、工作等认识的好友分开,那么分开以后,怎么知道究竟有多少 QQ 好友呢?

今天,以遍历各个分组的好友为例,介绍一下迭代器模式。

2. 迭代器模式实现

2.1 工程结构
iterator-pattern
└─ src
    ├─ main
    │    └─ java
    │    └─ org.design.pattern.iterator
    │       ├─ model
    │       │    ├─ Friend.java
    │       │    └─ Group.java
    │       └─ tool
    │            ├─ Iterator.java
    │            ├─ Collection.java
    │            └─ impl
    │                 ├─ IteratorImpl.java
    │                 └─ CollectionImpl.java
    └─ test
        └─ java
            └─ org.design.pattern.iterator
                  └─ IteratorTest.java
2.2 代码实现
2.2.1 实体类

QQ 好友

/**
 * QQ 好友
 */
@Getter
@Setter
@AllArgsConstructor
public class Friend {

    /**
     * 用户id
     */
    private String id;

    /**
     * 昵称
     */
    private String nickname;

    /**
     * 备注
     */
    private String noteName;
}

QQ 分组

/**
 * QQ 分组
 */
@Setter
@Getter
@AllArgsConstructor
public class Group {

    /**
     * 分组id
     */
    private String id;

    /**
     * 分组名称
     */
    private String name;

    /**
     * 好友列表
     */
    private CollectionImpl<Friend> friendList;

    /**
     * 添加好友
     *
     * @param friend 好友
     * @return boolean
     */
    public boolean addFriend(Friend friend) {
        return friendList.add(friend);
    }

    /**
     * 删除好友
     *
     * @param friend 好友
     * @return boolean
     */
    public boolean removeFriend(Friend friend) {
        return friendList.remove(friend);
    }
}
2.2.2 工具类

迭代器接口

/**
 * 迭代器接口
 *
 * @param <T>
 */
public interface Iterator<T> {

    /**
     * 是否有下一个节点
     *
     * @return boolean
     */
    boolean hasNext();

    /**
     * 获取下一个节点
     *
     * @return T
     */
    T getNext();
}

集合接口

/**
 * 集合接口
 * @param <E>
 */
public interface Collection<E> {

    /**
     * 创建迭代器
     *
     * @return Iterator<E>
     */
    Iterator<E> createIterator();

    /**
     * 添加集合元素
     *
     * @param e 集合元素
     * @return boolean
     */
    boolean add(E e);

    /**
     * 删除集合元素
     *
     * @param e 集合元素
     * @return boolean
     */
    boolean remove(E e);

    /**
     * 获取集合长度
     *
     * @return Integer
     */
    Integer size();

    /**
     * 获取集合元素
     *
     * @param index 索引
     * @return E
     */
    E get(Integer index);
}

迭代器实现类

/**
 * 迭代器实现类
 *
 * @param <E>
 */
public class IteratorImpl<E> implements Iterator<E> {

    private final CollectionImpl<E> groupCollection;

    private int currentIndex;

    public IteratorImpl(CollectionImpl<E>  groupCollection) {
        this.currentIndex = 0;
        this.groupCollection = groupCollection;
    }

    /**
     * 是否有下一个节点
     *
     * @return boolean
     */
    @Override
    public boolean hasNext() {
        return currentIndex < groupCollection.size();
    }

    /**
     * 获取下一个节点
     *
     * @return E
     */
    @Override
    public E getNext() {
        if (!hasNext()) {
            return null;
        }
        E e = groupCollection.get(currentIndex);
        currentIndex++;
        return e;
    }
}

集合实现类

/**
 * 集合实现类
 *
 * @param <E>
 */
public class CollectionImpl<E> implements Collection<E> {

    private final List<E> groupList;

    public CollectionImpl() {
        this.groupList = new ArrayList<>();
    }

    /**
     * 创建迭代器
     *
     * @return Iterator<E>
     */
    @Override
    public Iterator<E> createIterator() {
        return new IteratorImpl<E>(this);
    }

    /**
     * 添加集合元素
     *
     * @param e 集合元素
     * @return boolean
     */
    @Override
    public boolean add(E e) {
        return groupList.add(e);
    }

    /**
     * 删除集合元素
     *
     * @param e 集合元素
     * @return boolean
     */
    @Override
    public boolean remove(E e) {
        return groupList.remove(e);
    }

    /**
     * 获取集合长度
     *
     * @return Integer
     */
    @Override
    public Integer size() {
        return groupList.size();
    }

    /**
     * 获取集合元素
     *
     * @param index 索引
     * @return E
     */
    @Override
    public E get(Integer index) {
        return groupList.get(index);
    }
}
2.3 测试验证
2.3.1 测试验证类
/**
 * 迭代器测试
 */
public class IteratorTest {

    @Test
    public void testIterator() {
        CollectionImpl<Friend> friendCollectionOne = new CollectionImpl<>();
        friendCollectionOne.add(new Friend("1", "小可乐", "王明"));
        friendCollectionOne.add(new Friend("2", "阿毛今天睡醒了", "三毛"));
        friendCollectionOne.add(new Friend("3", "楚语吴歌", "夏亚"));

        CollectionImpl<Friend> friendCollectionTwo = new CollectionImpl<>();
        friendCollectionTwo.add(new Friend("1", "系鞋带进修员 ", "张涛"));

        CollectionImpl<Friend> friendCollectionThree = new CollectionImpl<>();
        friendCollectionThree.add(new Friend("1", "饕餮少女 ", "王霖"));

        CollectionImpl<Group> groupCollection = new CollectionImpl<>();
        groupCollection.add(new Group("1", "同学", friendCollectionOne));
        groupCollection.add(new Group("2", "网友", friendCollectionTwo));
        groupCollection.add(new Group("3", "同事", friendCollectionThree));

        Iterator<Group> groupIterator = groupCollection.createIterator();
        while (groupIterator.hasNext()) {
            Group group = groupIterator.getNext();
            System.out.printf("group id is %s, group name is %s", group.getId(), group.getName());
            System.out.println();
            Iterator<Friend> friendIterator = group.getFriendList().createIterator();
            while (friendIterator.hasNext()) {
                Friend friend = friendIterator.getNext();
                System.out.printf(
                        "Friend nickname is %s, Friend noteName is %s",
                        friend.getNickname(),
                        friend.getNoteName()
                );
                System.out.println();
            }
            System.out.println();
        }
    }
}
2.3.2 测试结果
group id is 1, group name is 同学
Friend nickname is 小可乐, Friend noteName is 王明
Friend nickname is 阿毛今天睡醒了, Friend noteName is 三毛
Friend nickname is 楚语吴歌, Friend noteName is 夏亚

group id is 2, group name is 网友
Friend nickname is 系鞋带进修员 , Friend noteName is 张涛

group id is 3, group name is 同事
Friend nickname is 饕餮少女 , Friend noteName is 王霖


Process finished with exit code 0

四、迭代器模式结构

迭代器模式结构图

  1. 迭代器(Iterator)接口声明了遍历集合所需的操作:获取下一个元素、获取当前位置和重新开始迭代等。
  2. 具体迭代器(Concrete Iterators)实现遍历集合的一种特定算法。迭代器对象必须追踪自身的遍历进度。这使得多个迭代器可以相互独立地遍历同一集合。
  3. 集合(Collection)接口声明一个或多个方法来获取与集合兼容的迭代器。

    注意:返回方法的类型必须被声明为迭代器接口,从而使具体集合可以返回各种不同种类的迭代器。

  4. 具体集合(Concrete Collections)会在客户端请求迭代器时返回一个特定的具体迭代器实体。
  5. 客户端(Client)通过集合和迭代器的接口与两者进行交互。这样一来客户端无需与具体类耦合,允许同一客户端代码使用各种不同的集合和迭代器

    客户端通常不会自行创建迭代器,而是会从集合中获取。但在特定情况下,客户端可以直接创建一个迭代器。

设计模式并不难学,其本身就是多年经验提炼出的开发指导思想,关键在于多加练习,带着使用设计模式的思想去优化代码,就能构建出更合理的代码。

源码地址:https://github.com/yiyufxst/design-pattern-java

参考资料:
小博哥重学设计模式:https://github.com/fuzhengwei/itstack-demo-design
深入设计模式:https://refactoringguru.cn/design-patterns/catalog


易羽fxst
158 声望5 粉丝