轻松搞定常见的23中设计模式:每日学一个设计模式-Iterator模式(暂时停更修炼)

在聊Iterator模式前我们先来做一个小小的练习:

需求如下:我们需要在一个书架中放一堆的书籍,之后依次打印输出书籍的价格:

看到这个任务其实但凡会点编程的兄弟就知道怎么实现

  1. 定义一个书架类:BookShelf,类中有存放Book的数组,有存放书籍的方法
  2. 定义一个书籍类:Book,类中有价格字段,有获取书籍价格的具体方法,和对应的满参构造方法
  3. 有一个主类,在主类中实现相应的业务逻辑:定义书架,向书架中放书,之后for循环遍历书的过程中依次打印对应书籍的价格

 实不相瞒这确实是一个比较简单的问题,但是我今天就是想要将这个过程"复杂化"

下面是我的实现思路(先看懂代码,之后我再来解释一下这和今天所说的Iterator设计模式有什么关系):

以下是我的项目目录结构:

 解释:

  • AggreGate:表示集合的接口(是所有要定义的集合的抽象,方法代表共性方法:表示可以遍历)
/**
 * 表示集合的接口,实现该接口之后可以拥有iterator方法,调用该方法可以创建出对应的迭代器,用于遍历集合
 */
public interface AggreGate {
    public abstract MyIterator iterator();
}
  • Book:书籍类
package com.aihua.model.iterator;

public class Book {
    public Integer price;
    public Book(Integer price){
        this.price=price;
    }
    public Integer getPrice(){
        return this.price;
    }
}
  • BookShelf:书架类(既然是存放书籍的,那必然要实现集合类接口,因此要重写iterator方法,在这里我们返回的是MyIterator类型,具体返回的是一个MyIterator的实现类对象BookShelfIterator,里面定义了具体的遍历实现业务,至于为什么要用MyIterator接收,其好处后面会解释)
package com.aihua.model.iterator;



public class BookShelf implements AggreGate {
    private Book[] books;
    private int last=0;
    public BookShelf(int maxSize){
        this.books=new Book[maxSize];
    }
    public Book getBookByIndex(int index){
        return books[index];
    }
    public void addBook(Book book){
        this.books[last]=book;
        last++;
    }
    public int getLength(){
        return last;
    }

    public MyIterator iterator() {
       return  new BookShelfIterator(this);
    }
}
  • BookShelfIterator(具体的书架迭代器,用于书写书架这个集合具体的遍历功能)
package com.aihua.model.iterator;

import java.util.Iterator;

public class BookShelfIterator implements MyIterator {
    private BookShelf bookShelf;
    private int index;
    public BookShelfIterator(BookShelf bookShelf) {
        this.bookShelf=bookShelf;
        this.index=0;
    }

    @Override
    public boolean hasNext() {
        if(index<bookShelf.getLength()){
            return true;
        }else {
            return false;
        }
    }

    @Override
    public Object next() {
        Book book = bookShelf.getBookByIndex(index);
        index++;
        return book;
    }
}
  • MyIterator:一个迭代器,实现之后可以遍历功能(我这里只写了两个抽象方法:hasNext,next,第一个用于判断集合是否存在下一个元素,next用于返回集合中当前位置的元素,并指向下一个元素的位置)
package com.aihua.model.iterator;

public interface MyIterator {
    public abstract boolean hasNext();
    public abstract Object next();
}
  • MyIteratorDemo:主类,用于具体实现整个功能,代码比较简单,就是向书架中存放书籍,之后将书架中的书籍价格打印输出
package com.aihua.model.iterator;

import java.util.Iterator;

public class MyIteratorDemo {
    public static void main(String[] args) {
        BookShelf bookShelf = new BookShelf(4);
        bookShelf.addBook(new Book(1));
        bookShelf.addBook(new Book(2));
        bookShelf.addBook(new Book(3));
        bookShelf.addBook(new Book(4));
        MyIterator iterator = bookShelf.iterator();
        while (iterator.hasNext()){
            Book book = (Book)iterator.next();
            System.out.println(book.getPrice());
        }

    }
}

至此,所有的代码工作其实已经完成了,但是还有些细节上的问题,我们下面依次解释清除。

在此之前我们可以对比一下两种编码的实现方案,一眼便知,必然是第一种写起来更加简单,那么为什么要使用第二种呢,其实问出这个问题的根本原因还是在于,我们考虑的这是这么一个具体的问题,而不是具体问题的抽象,我们只看到了向书架中放数据,向书架中取数据(遍历)这个过程。

而Iterator则把问题思考的更加全面了,他看到的是,暑假是一个集合,书架取书为集合的遍历,因此才会将两者抽象出来,一个为集合接口(为我们上文的AggreGate),另一个为遍历用的接口(MyIterator),你要什么功能就直接去实现对应的接口,就比如你在一个大的图书管理系统中,你要遍历的地方很多,比如要遍历很多的读者,很多的分类,那么你在写for循环遍历的时候必然会使用到与之相关类的方法,这样一来,一是代码量十分的大,其次就是代码之间的耦合性非常的强,注意!实际开发中代码的一个重要的评判标准就是是否做到了:“高聚合,低耦合”,而Iterator就很好的解决了这个问题。

请看如下代码:

这是主类中遍历书架的时候用到的代码,我们始终没有用到和Book或者BookShelf,BookShelfIterator相关的方法,我们用的都是iterator的方法进行编程,也就是看代码的人一眼就知道这里在干什么。而且这对Bookself的调用者来说实在是太友好了,根本不需要指导BookShelf具体改怎么实现,用哪些方法去实现遍历这些操作,只要调用iterator方法就可以生产对应遍历用的迭代器。就算以后你BookShelf里面代码要进行变动,具体实现逻辑有了大变动,你这块的代码还是不需要变动的,代码健壮性还是非常强的。当然,具体编辑BookShelf迭代器的人员肯定是要知道BookShelf的实现细节的,不然下面的代码根本没法写嘛。

至此Iterator模式基本就讲完了,其实熟悉java集合框架的人员就知道,Iterator模式的应用还是非常广泛的,比如:

  1. java.util.Collection 接口继承了java.lang.Iterable 接口,这代表着所有 Collection 的子类都支持通过 Iterator 遍历它们的元素。

  2. ArrayList、LinkedList、Vector、HashSet、LinkedHashSet、TreeSet 等多个集合类都实现了 Iterator 接口,以支持使用 for-each 循环来遍历集合中的元素。

  3. HashMap 和 Hashtable 等映射结构的集合类也提供了 Iterator 接口以支持对集合中的键和值进行迭代操作。

总之,Java编程语言标准库中的很多集合实现都使用了Iterator模式,开发人员可以通过Iterator接口及其方法定义获取统一的遍历方式,从而使得代码更加灵活和易于维护。

也许在这个具体的例子中体现不出他的作用,但是一但将格局打开,那一定可以发现他的好处,不然你平时在使用java提供的集合时,哪些遍历方法是怎么统一的,其实就是具体的细节通过这种方式进行封装了,而使用人员也根本不需要了解实现细节,便可以触类旁通,学一个集合的遍历方式便可以掌握别的类似的集合的实现方式,这种思想无论对于初学者还是有一定开发经验的人都是非常重要的(资深大佬除外hhhhh~)

如果你喜欢我写的文章麻烦点个赞哦!

我后续会不断更新各种技术博客(当然,先把23中设计模式全讲完再说咯!)

猜你喜欢

转载自blog.csdn.net/2301_76875881/article/details/130833957
今日推荐