Design(一)-Iterator设计模式

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模式

借鉴

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,692评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,482评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,995评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,223评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,245评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,208评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,091评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,929评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,346评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,570评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,739评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,437评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,037评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,677评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,833评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,760评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,647评论 2 354

推荐阅读更多精彩内容