Java设计模式学习记录-迭代器模式

前言

这次要介绍的是迭代器模式,也是一种行为模式。我现在觉得写博客有点应付了,前阵子一天一篇,感觉这样其实有点没理解透彻就写下来了,而且写完后自己也没有多看几遍,上次在面试的时候被问到java中的I/O的各种实现用到了什么设计模式,我愣是想半天没想出来了,人家还给提示了我也没想出来,最后还是面试官给出的答案,是装饰模式,听到答案后就恍然大悟了,前两天刚看了装饰模式,还写下了I/O操作中的各种类都是用到了装饰模式,后来想想两方面原因造成的当时没回答出来,一是面试时紧张就容易想不起来,二是对设计模式理解的还是不够透彻。所以以后宁可写博客慢一些也要将自己写的东西理解透彻了。

迭代器模式

概念介绍

迭代器模式,又称游标模式。这种模式提供一种方法访问一个容器对象中各个元素,而又不需要暴露该对象的内部细节。这种模式其实我们日常开发中也很常见,例如下面的场景:

        java.util.Iterator<String> it = list.iterator();
        
        while (it.hasNext()){
            //using "it.next();" do some business logic
        }

这样来理解简单一些,下面还是通过具体的场景例子来实现迭代器模式。

举例

一个书架上放着好几本书,现在我想知道书架上都有哪些书,并且都把书名打印出来。那么书架就可以具有迭代的功能,能把它存放的所有书籍都迭代出来。用代码实现如下:

定义一个迭代器接口,包含检测是否还有下一个元素的方法和获得下一个元素的方法

/**
 * 迭代器接口
 */
public interface Iterator {

    /**
     * 检测是否还有下一个元素
     * @return
     */
    public abstract boolean hasNext();

    /**
     * 获得下一个元素
     * @return
     */
    public abstract Object next();

}

定义含有迭代器对象的接口

/**
 * 只有实现此接口的才可以获得迭代器对象
 */
public interface Aggregate {
    /**
     * 获得迭代器对象
     * @return
     */
    public abstract Iterator iterator();
}

书籍类

/**
 * 书籍类
 */
public class Book {
    
    //书籍名称
    private String name = "";

    public Book(String name){
        this.name = name;
    }

    /**
     * 获得书籍名称
     * @return
     */
    public String getName(){
        return name;
    }
}

书架类

/**
 * 书架类
 */
public class BookShelf implements Aggregate{

    private Book[] books;

    private int last = 0;

    public BookShelf(int maxSize){
        this.books = new Book[maxSize];
    }

    /**
     * 获得书籍
     * @param index
     * @return
     */
    public Book getBookAt(int index){

        return books[index];

    }

    /**
     * 添加书籍
     * @param book
     */
    public void appendBook(Book book){
        this.books[last] = book;
        last++;
    }

    /**
     * 获得书架上的书籍数量
     * @return
     */
    public int getLength(){
        return books.length;
    }

    /**
     * 获得书架迭代器对象
     * @return
     */
    @Override
    public Iterator iterator(){
        return new BookShelfIterator(this);
    }
}

书架迭代器

/**
 * 书架迭代器
 */
public class BookShelfIterator implements Iterator {

    private BookShelf bookShelf;
    private int index;

    public BookShelfIterator(BookShelf bookShelf){
        this.bookShelf = bookShelf;
        this.index = 0;
    }

    /**
     * 检测是否还有下一本书
     * @return
     */
    @Override
    public boolean hasNext() {
        if(index<bookShelf.getLength()){
            return true;
        }else {
            return false;
        }
    }

    /**
     * 返回下一本书
     * @return
     */
    @Override
    public Object next() {
        Book book = bookShelf.getBookAt(index);
        index++;
        return book;
    }
}

测试类

public class Client {


    public static void main(String[] args) {
        //创建一个书架
        BookShelf bookShelf = new BookShelf(5);
        //向书架中添加书籍
        bookShelf.appendBook(new Book("深入理解Java虚拟机"));
        bookShelf.appendBook(new Book("Java编程思想"));
        bookShelf.appendBook(new Book("高性能MySQL"));
        bookShelf.appendBook(new Book("Effective Java 中文版"));
        bookShelf.appendBook(new Book("数据结构与算法分析Java语言描述"));
        //获得书架迭代器
        Iterator iterator = bookShelf.iterator();
        //迭代
        while (iterator.hasNext()){
            Book book = (Book) iterator.next();
            System.out.println(book.getName());
        }

    }

}

运行结果

深入理解Java虚拟机
Java编程思想
高性能MySQL
Effective Java 中文版
数据结构与算法分析Java语言描述

上面的这个例子就是实现了迭代器模式,可以看出来是在客户端和容器间加入了迭代器,这样就很好的避免容器内部细节的暴露,而且也使得设计符合“单一职责原则”。

迭代器模式的结构

迭代器模式主要由以下角色组成

抽象迭代器角色(Iterator):抽象迭代器角色定义访问和遍历元素的接口。上面例子中的Iterator接口就是代表的这个角色。

具体迭代器角色(Concrete Iterator):具体迭代器角色要实现迭代器接口, 并要记录遍历中的当前位置。上面例子中BookShelfIterator类就是代表的这个角色。

容器角色(Aggregate):容器角色负责提供创建具体迭代器角色的接口。上面的例子中的Aggregate接口代表的就是这个角色。

具体容器角色(Concrete Aggregate):具体容器角色实现创建具体迭代器角色的接口,这个具体迭代器角色与该容器的结构相关。上面例子中书架类BookShelf

代表的就是这个角色。

总结

迭代器模式是一种使用频率非常高的设计模式,通过引入迭代器可以将数据的遍历功能从聚合对象中分离出来,聚合对象只负责存储数据,而遍历数据由迭代器实现完成。Java语言类库中已经实现了迭代器模式,在实际开发中我们直接使用已经定义好的迭代器就可以了,像List、Set等集合都可以直接使用。

优点

1、它支持以不同的方式遍历一个聚合对象,在同一个聚合对象上可以定义多种遍历方式。替换迭代器就可以切换遍历方法。

2、迭代器简化了聚合类。聚合对象可以不用自己再提供遍历方法。

3、在迭代器模式中由于引入了抽象层,增加新的聚合类和迭代器类都很方便,无须修改原有代码,满足“开闭原则”的要求。

缺点

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

2、抽象迭代器设计难度相对较大,需要充分考虑到系统将来的扩展,,例如JDK内置迭代器Iterator就无法实现逆向遍历,如果需要实现逆向遍历,只能通过其子类ListIterator等来实现,而ListIterator迭代器无法用于操作Set类型的聚合对象。

适用场景

在以下情况可以考虑使用迭代器模式

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

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

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

想了解更多的设计模式请查看Java设计模式学习记录-GoF设计模式概述

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java学习网

学习Java需吃透这些基本概念

学习好比盖房子,打地基好很重要,房了能盖多高关键看地基;学习同样道理,基础知识是以后学习一切技术的必要条件,我们在准备学习一门开发语言时,首先要学习它的基础,不...

258100
来自专栏老九学堂

C语言干货,新手入门必看,基础知识大汇总!

学习C语言始终要记住“曙光在前头”和“千金难买回头看”,“千金难买回头看”是学习知识的重要方法,就是说,学习后面的知识,不要忘了回头弄清遗留下的问题和加深理解前...

417110
来自专栏DannyHoo的专栏

iOS开发中swift中的类方法和实例方法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010105969/article/details/...

13230
来自专栏编程

C语言干货,新手入门必看,基础知识大汇总!

习C语言始终要记住“曙光在前头”和“千金难买回头看”,“千金难买回头看”是学习知识的重要方法,就是说,学习后面的知识,不要忘了回头弄清遗留下的问题和加深理解前面...

30150
来自专栏java架构师

读【重构】读书笔记之一 代码的坏味道

一、重复的代码: 包含完全重复、部分重复、以及程序不同结果相同 1)一个类的两个函数有相同的表达式  ---提取方法 2)两个互为兄弟的子类含有相同表达式---...

27270
来自专栏C/C++基础

STL四种智能指针

STL一共给我们提供了四种智能指针:auto_ptr、unique_ptr、shared_ptr和weak_ptr,auto_ptr是C++98提供的解决方案,...

42930
来自专栏Java爬坑系列

【Java入门提高篇】Day16 Java异常处理(上)

  异常嘛,顾名思义就是不正常,(逃),是Java程序运行时,发生的预料之外的事情,它阻止了程序按照程序员的预期正常执行。

367120
来自专栏青蛙要fly的专栏

Android技能树 — 排序算法基础小结

现在安卓面试,对于算法的问题也越来越多了,要求也越来越多,特别是排序,基本必考题,而且还动不动就要手写,所以陆续要写算法的文章,也正好当自己学习。o(╥﹏╥)o

9220
来自专栏Java爬坑系列

【Java入门提高篇】Day16 Java异常处理(上)

16450
来自专栏编程

C语言/C加加新手入门学习经验资料分享,基础知识大汇总!

C语言是面向过程的,而C++是面向对象的 相信这么努力的你 已经置顶了我 学习C语言始终要记住“曙光在前头”和“千金难买回头看”,“千金难买回头看”是学习知识的...

25290

扫码关注云+社区

领取腾讯云代金券