美文网首页
Design(一)-Iterator设计模式

Design(一)-Iterator设计模式

作者: TheAPICaller | 来源:发表于2019-02-06 20:08 被阅读0次

Iterator设计模式

简介:

Iterator设计模式在数据集合中按照顺序遍历集合. 英语单词Iterate有反复做某件事情的意思, 称为迭代器

例子说明:

名字 说明
Aggregate 表示集合的接口
Iterator 遍历集合的接口
Book 表示书的类
BookShelf 表示书架的类
BookShelfIterator 遍历书架的类
DesignApplicationTests 所有的测试方法类

代码

Aggregate接口(Aggregate.java)

/**
 * 迭代器类
 *
 * @author MARKCC
 * @date 2019/2/6-16:32
 * @email markerccc@163.com
 */
public interface Aggregate {
    /**
     * 用于遍历集合的迭代器方法
     *
     * @return 迭代器类
     */
    Iterator iterator();
}

Iterator接口(Iterator.java)

/**
 * 用于遍历集合中的元素
 *
 * @author MARKCC
 * @date 2019/2/6-16:33
 * @email markerccc@163.com
 */
public interface Iterator {
    /**
     * 当集合中存在下一个元素的时候,该方法返回true
     *
     * @return Boolean
     */
    Boolean hasNext();

    /**
     * 返回的是集合中的下一个元素
     *
     * @return 集合中的下一个元素
     */
    Object next();
}

Book类(Book.java)

package com.mark.model.entity;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.*;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.util.Date;

/**
 * 书
 *
 * @author MARKCC
 * @date 2019/2/6-16:35
 * @email markerccc@163.com
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@TableName("book")
public class Book extends Model<Book> {

    private static final long serialVersionUID = 1L;

    @TableId
    private Long id;
    @TableField("create_time")
    private Date createTime;
    @TableField(value = "update_time", update = "now()")
    private Date updateTime;
    @TableField("del_flag")
    private String delFlag;
    @TableField("name")
    private String name;

    @Override
    protected Serializable pkVal() {
        return this.id;
    }
}

BookShelf类(BookShelf.java)

/**
 * 书架
 *
 * @author MARKCC
 * @date 2019/2/6-16:42
 * @email markerccc@163.com
 */
public class BookShelf implements Aggregate {
    private transient Book[] books;
    /**
     * ArrayList中用到了类似的用法, 请看modCount, modCount的用处是防止集合在遍历的时候被修改, 产生并发修改异常
     */
    private int last = 0;

    private int size;

    /**
     * 指定书架的最大容量
     *
     * @param maxsize 最大容量
     */
    public BookShelf(Integer maxsize) {
        this.size = maxsize;
        this.books = new Book[maxsize];
    }

    /**
     * 拿到索引位置上的书
     *
     * @param index 索引
     * @return 该索引上的书
     */
    public Book getBookAt(int index) {
        //这里借鉴ArrayList, 防止产生索引越界
        if (index >= size) {
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }
        return books[index];
    }

    /**
     * 添加书本的方法
     *
     * @param book 书本
     */
    public void appendBook(Book book) {
        if (last >= size) {
            throw new IndexOutOfBoundsException(outOfBookOutMsg(last));
        }
        this.books[last] = book;
        last++;
    }

    /**
     * 获得长度
     *
     * @return
     */
    public int getLength() {
        return last;
    }

    @Override
    public Iterator iterator() {

        return new BookShelfIterator(this);
    }

    private String outOfBoundsMsg(int index) {
        // 返回当前的索引, 和元素个数
        return "Index: " + index + ", Size: " + size;
    }

    private String outOfBookOutMsg(int index) {
        return "Index: " + index + ", 书架Size: " + size;
    }
}

BookShelfIterator类(BookShelfIterator.java)

/**
 * @author MARKCC
 * @date 2019/2/6-16:58
 * @email markerccc@163.com
 */
public class BookShelfIterator implements Iterator {
    private BookShelf bookShelf;
    private int index;

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

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

    @Override
    public Object next() {
        Book book = bookShelf.getBookAt(index);
        index++;
        return book;
    }
}

测试方法:

/**
 * 迭代器设计模式
 */
@Test
public void iteratorTest() {
    BookShelf bookShelf = new BookShelf(3);
    bookShelf.appendBook(new Book(1L, new Date(), null, "0", "A"));
    bookShelf.appendBook(new Book(2L, new Date(), null, "0", "B"));
    bookShelf.appendBook(new Book(3L, new Date(), null, "0", "C"));
    Iterator iterator = bookShelf.iterator();
    while (iterator.hasNext()) {
        Book book = (Book) iterator.next();
        System.out.println(book.getName());
    }
}

分析

1. Iterator(迭代器)

该角色负责定义按顺序逐个遍历元素的接口(API)

方法 作用
hasNext 用于判断是否存在下一个元素
next 用于获取元素

2. ConcreteIterator(具体的迭代器)

该角色负责实现Iterator角色所定义的接口(API)

扮演者 作用
BookShelfIterator 该角色包含了遍历集合所需的信息
字段 作用
bookShelf 实例
index 指向的书的下标

3. Aggreagte(集合)

该角色负责创建Iterator角色的接口(API)

作用
它会创建出"按顺序访问保存在我内部元素的人
扮演者 作用
Aggregate 定义了iterator()

4. ConcreateAggregate(具体的集合)

该角色负责实现Aggregate角色所定义的接口(API)

作用
它会创建出具体的Iterator角色, 即ConcreteIterator角色
扮演者 作用
BookShelf 实现了Iterator方法

总结

1. 不管怎么如何变化, 都可以使用Iterator

while (iterator.hasNext()) {
    Book book = (Book) iterator.next();
    System.out.println(book.getName());
}
分析1 :
这里只使用了IteratorhasNext()next(), 并没有调用BookShelf的方法. 也就是说, 这里的while循环并不依赖于BookShelf实现
分析2 :
如果编写BookShelf的开发人员决定放弃数组来管理书本, 而是使用集合取代, 不管BookShelf如何变化, 只要BookShelfIterator都能正确的返回Iterator实例, 即不对上面的while循环做任何修改, 代码可以正常工作
分析3:
设计模式的作用就是帮助我们编写可复用的类. 所谓可复用, 就是将类实现为组件, 当一个组件发生改变时, 不需要对其他的组件进行修改, 或者只需要很小的修改即可, 这就是为什么Iterator的方法返回值是Iterator类型了, 而不是BookShelfIterator类了

2. 难以理解的抽象类和接口

分析:
人们常常使用ConcreateAggregate角色和ConcreateIterator角色编程, 而不使用AggregateIterator接口, 他们总想用具体的类来解决所有的问题. 这样很容易导致类之间的强耦合, 难以复用, 为了弱化类之间的耦合, 进而使类更加容易作为组件被再次利用, 需要常常使用抽象类和接口

3. 对应关系

Aggregate Iterator
ConcreateAggreagte ConcreateIterator
分析:
如果BookShelf的实现发生了改变, 即getBookAt()发生改变, 我们必须修改BookShelfIterator

4. 下一个

分析:
next()方法是返回当前的元素, 并指向下一个元素

5. 最后一个

分析:
hasNext() 确认接下来是否可以调用next方法

6. 多个Iterator

分析:
将遍历功能置于Aggregate角色之外Iterator模式的一个特征. 根据这个特征, 可以针对一个ConcreateAggregate角色编写多个ConcreateIterator角色, 即一个集合可以编写多个迭代器

7. 迭代器的种类多种多样

种类
从最后开始向前遍历
即可以从前向后遍历, 也可以从后向前遍历(即有next()也有previous()
指定下标进行跳跃式的遍历

8. 不需要deleteIterator

分析:
Java中, 没有被使用的对象实例将会自动被删除(GC), 因此, 在Iterator中不需要与其对应的deleteIterator()

9. 相关的设计模式

Iterator模式 没有在Iterator接口中对取出元素进行处理
Visitor模式 遍历集合的过程中, 对元素进行相同的处理
Composite模式 具有递归结构的模式, 在其中使用Iterator模式比较困难
Factory Method模式 Iterator方法中生成Iterator的实例时可能会使用Factory Method模式
分析:
在遍历集合的过程中对元素进行固定的处理是常有的, Visitor模式正是为了应对这种需求出现的, 在访问元素集合的过程中对元素进行相同处理, 这种模式就是Visitor模式

借鉴

图解设计模式(结城浩 著)

相关文章

网友评论

      本文标题:Design(一)-Iterator设计模式

      本文链接:https://www.haomeiwen.com/subject/neuisqtx.html