设计模式——(16)迭代器模式

1、定义

提供一种方法来访问聚合对象,而不用暴露这个对象的内部表示,其别名为游标(Cursor)。迭代器模式是一种对象行为型模式。

2、UML类图

  • 抽象容器角色(Aggregate):负责提供创建具体迭代器角色的接口,一般是一个接口,提供一个iterator()方法,例如java中的Collection接口,List接口,Set接口等。

  • 具体容器角色(ConcreteAggregate):就是实现抽象容器的具体实现类,比如List接口的有序列表实现ArrayList,List接口的链表实现LinkedList,Set接口的哈希列表的实现HashSet等。

  • 抽象迭代器角色(Iterator):负责定义访问和遍历元素的接口。

  • 具体迭代器角色(ConcreteIterator):实现迭代器接口,并要记录遍历中的当前位置。

3、实例

a、背景:

正向遍历迭代器实现

  • 提供一种可以遍历对象集合的方式,又称为:游标cursor模式

  • 聚合对象:存储数据,这里我在代码中定义成Container接口,用于获取迭代器对象

  • 迭代器:遍历数据

b、实例

步骤一创建抽象了迭代器类,用于规划有哪些操作

public interface MyIterator {
     // 迭代器初始值,如果有的地方需要,移动到-1位置,方便某些操作的统一性
     void moveToMinusOne();

     boolean moveToFirst(); // 移动游标到第一个位置

     boolean next(); // 移动游标到下一个位置

     boolean hasNext(); // 判断游标是否有下一个位置

     boolean isFirst(); // 判断当前游标是否是第一个位置

     boolean isLast(); // 判断当前游标是否是最后一个位置

     Object getCurrentObject(); // 获取当前游标所指向的对象
}

步骤二:创建抽象的容器

public interface AggregateContainer {
    MyIterator getMyIterator();
}

步骤三:创建具体的容器类实现抽象的聚合容器类,由于迭代器的实现是为了对该具体容器的使用和操作,所以具体迭代器类在具体容器类中以内部类的方式存在,并且实现抽象迭代器接口

public class ConcreteContainer implements AggregateContainer {

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

     public List<Object> getList() {
           return list;
     }

     public void setList(List<Object> list) {
           this.list = list;
     }

     void addObject(Object object) {
           list.add(object);
     }

     void removeObject(Object object) {
           list.remove(object);
     }

     @Override
     public MyIterator getMyIterator() {
           return new ConcreteIterator();
     }

     // 使用内部类的定义方式,让ConcreteIterator服务于ConcreteContainer
     private class ConcreteIterator implements MyIterator {

           private int cursor = -1; // 用于记录遍历时的位置

           public void moveToMinusOne() {
                cursor = -1;
           }

           public boolean moveToFirst() {
                if (list.size() >= 1) {
                      cursor = 0;
                      return true;
                }
                return false;

           }

           public boolean next() {
                if (hasNext()) {
                      cursor++;
                      return true;
                }
                return false;
           }

           public boolean hasNext() {
                return cursor + 1 < list.size();
           }

           public boolean isFirst() {
                return cursor == 0;
           }

           public boolean isLast() {
                return cursor == list.size() - 1;
           }

           public Object getCurrentObject() {
                if (cursor >= 0 && cursor < list.size())
                      return list.get(cursor);
                else
                      return null;
           }
     }
}

步骤四:客户端测试

public class Client {
     public static void main(String[] args) {
           ConcreteContainer carNameContainer = new ConcreteContainer();
           // 测试添加
           carNameContainer.addObject("byd");
           carNameContainer.addObject("bmw");
           carNameContainer.addObject("benz");
           carNameContainer.addObject("audi");
           // 测试删除
           carNameContainer.removeObject("bmw");
           // 获取迭代器,测试isFist()与isLast()
           MyIterator myIterator = carNameContainer.getMyIterator();
           System.out.println("Is first ? : " + myIterator.isFirst());
           System.out.println("Move to first : " + myIterator.moveToFirst());
           System.out.println("Is first now ? : " + myIterator.isFirst());
           // 遍历相关函数测试
           System.out.println("--遍历方法1--");
           if (myIterator.moveToFirst()) {
                do {
                      System.out.println(myIterator.getCurrentObject());
                } while (myIterator.next()); // next()内部先判断是否有next,即hasNext(),有则移动到下一个位置并返回真
           }
           System.out.println("Is last ? : " + myIterator.isLast());

           System.out.println("--遍历方法2--");
           if (myIterator.moveToFirst()) {
                System.out.println(myIterator.getCurrentObject());
                while (myIterator.next()) {
                      System.out.println(myIterator.getCurrentObject());
                }
           }
           System.out.println("Is last ? : " + myIterator.isLast());

           System.out.println("--遍历方法3--");
           myIterator.moveToMinusOne();
           while (myIterator.next()) {
                System.out.println(myIterator.getCurrentObject());
           }
           System.out.println("Is last ? : " + 
myIterator.isLast());
     }
}

4、优点

  • 简化了遍历方式,对于对象集合的遍历,还是比较麻烦的,对于数组或者有序列表,我们尚可以通过游标来取得,但用户需要在对集合了解很清楚的前提下,自行遍历对象,但是对于hash表来说,用户遍历起来就比较麻烦了。而引入了迭代器方法后,用户用起来就简单的多了。

  • 可以提供多种遍历方式,比如说对有序列表,我们可以根据需要提供正序遍历,倒序遍历两种迭代器,用户用起来只需要得到我们实现好的迭代器,就可以方便的对集合进行遍历了。

  • 封装性良好,用户只需要得到迭代器就可以遍历,而对于遍历算法则不用去关心。

5、缺点

  • 由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。

  • 抽象迭代器的设计难度较大,需要充分考虑到系统将来的扩展,例如JDK内置迭代器Iterator就无法实现逆向遍历,如果需要实现逆向遍历,只能通过其子类ListIterator等来实现,而ListIterator迭代器无法用于操作Set类型的聚合对象。在自定义迭代器时,创建一个考虑全面的抽象迭代器并不是件很容易的事情。

6、适用场景

  • 访问一个聚合对象的内容而无须暴露它的内部表示。将聚合对象的访问与内部数据的存储分离,使得访问聚合对象时无须了解其内部实现细节。

  • 需要为一个聚合对象提供多种遍历方式。

  • 为遍历不同的聚合结构提供一个统一的接口,在该接口的实现类中为不同的聚合结构提供不同的遍历方式,而客户端可以一致性地操作该接口。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DF10F-0001A

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值