DESIGN DESIGN
  • 架构
  • 设计模式
  • 重构
  • UML
GitHub (opens new window)
  • 架构
  • 设计模式
  • 重构
  • UML
GitHub (opens new window)
  • 架构

  • 设计模式

    • 设计模式概述
    • 设计模式之简单工厂模式
    • 设计模式之工厂方法模式
    • 设计模式之抽象工厂模式
    • 设计模式之建造者模式
    • 设计模式之原型模式
    • 设计模式之单例模式
    • 设计模式之适配器模式
    • 设计模式之桥接模式
    • 设计模式之组合模式
    • 设计模式之装饰模式
    • 设计模式之外观模式
    • 设计模式之享元模式
    • 设计模式之代理模式
    • 设计模式之模板方法模式
    • 设计模式之命令模式
    • 设计模式之迭代器模式
      • 意图
      • 适用场景
      • 结构
        • 结构说明
        • 结构代码范式
      • 伪代码
      • 与其他模式的关系
      • 案例
      • 参考资料
    • 设计模式之观察者模式
    • 设计模式之解释器模式
    • 设计模式之中介者模式
    • 设计模式之职责链模式
    • 设计模式之备忘录模式
    • 设计模式之策略模式
    • 设计模式之访问者模式
    • 设计模式之状态模式
    • 面向对象原则
  • 重构

  • DDD

  • UML

  • 设计
  • 设计模式
dunwu
2015-01-19
目录

设计模式之迭代器模式

# 设计模式之迭代器模式

# 意图

迭代器模式(Iterator) 是一种行为设计模式, 让你能在不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素。

# 适用场景

  • 当集合背后为复杂的数据结构, 且你希望对客户端隐藏其复杂性时 (出于使用便利性或安全性的考虑), 可以使用迭代器模式。
  • 使用该模式可以减少程序中重复的遍历代码。
  • 如果你希望代码能够遍历不同的甚至是无法预知的数据结构, 可以使用迭代器模式。

# 结构

img

# 结构说明

  1. 迭代器 (Iterator) 接口声明了遍历集合所需的操作: 获取下一个元素、 获取当前位置和重新开始迭代等。
  2. 具体迭代器 (Concrete Iterators) 实现遍历集合的一种特定算法。 迭代器对象必须跟踪自身遍历的进度。 这使得多个迭代器可以相互独立地遍历同一集合。
  3. 集合 (Collection) 接口声明一个或多个方法来获取与集合兼容的迭代器。 请注意, 返回方法的类型必须被声明为迭代器接口, 因此具体集合可以返回各种不同种类的迭代器。
  4. 具体集合 (Concrete Collections) 会在客户端请求迭代器时返回一个特定的具体迭代器类实体。 你可能会琢磨, 剩下的集合代码在什么地方呢? 不用担心, 它也会在同一个类中。 只是这些细节对于实际模式来说并不重要, 所以我们将其省略了而已。
  5. 客户端 (Client) 通过集合和迭代器的接口与两者进行交互。 这样一来客户端无需与具体类进行耦合, 允许同一客户端代码使用各种不同的集合和迭代器。
    • 客户端通常不会自行创建迭代器, 而是会从集合中获取。 但在特定情况下, 客户端可以直接创建一个迭代器 (例如当客户端需要自定义特殊迭代器时)。

# 结构代码范式

Iterator : 定义访问元素的接口。

interface Iterator {
    public Object first();
    public Object next();
    public boolean isDone();
    public Object currentItem();
}

ConcreteIterator : 实现 Iterator 接口。记录当前访问的元素在集合中的位置信息。

class ConcreteIterator implements Iterator {
    private int current = 0;
    private ConcreteAggregate aggregate;

    public ConcreteIterator(ConcreteAggregate aggregate) {
        this.aggregate = aggregate;
    }

    @Override
    public Object first() {
        return aggregate.get(0);
    }

    @Override
    public Object next() {
        current++;
        if (current < aggregate.size()) {
            return aggregate.get(current);
        }
        return null;
    }

    @Override
    public boolean isDone() {
        return (current >= aggregate.size()) ? true : false;
    }

    @Override
    public Object currentItem() {
        return aggregate.get(current);
    }
}

Aggregate : 定义创建 Iterator 对象的接口。

interface Aggregate {
    public Iterator CreateIterator();
}

ConcreteAggregate : 实现 Iterator 接口,返回一个合适的 ConcreteIterator 实例。

class ConcreteAggregate implements Aggregate {
    private List<Object> items = new ArrayList<Object>();

    @Override
    public Iterator CreateIterator() {
        return new ConcreteIterator(this);
    }

    public int size() {
        return items.size();
    }

    public Object get(int index) {
        return items.get(index);
    }

    public void set(int index, Object element) {
        items.set(index, element);
    }

    public void add(Object element) {
        items.add(element);
    }
}

客户端

public class IteratorPattern {
    public static void main(String[] args) {
        ConcreteAggregate aggregate = new ConcreteAggregate();
        aggregate.add("张三");
        aggregate.add("李四");
        aggregate.add("王五");
        aggregate.add("赵六");

        Iterator iter = new ConcreteIterator(aggregate);
        Object item = iter.first();
        System.out.println("第一个人是:" + item);
        System.out.println("所有人的名单是:");
        while (!iter.isDone()) {
            System.out.println(iter.currentItem());
            iter.next();
        }
    }
}

输出

第一个人是:张三
所有人的名单是:
张三
李四
王五
赵六

# 伪代码

在本例中, 迭代器模式用于遍历一个封装了访问微信好友关系功能的特殊集合。 该集合提供使用不同方式遍历档案资料的多个迭代器。

img

“好友 (friends)” 迭代器可用于遍历指定档案的好友。 “同事 (colleagues)” 迭代器也提供同样的功能, 但仅包括与目标用户在同一家公司工作的好友。 这两个迭代器都实现了同一个通用接口, 客户端能在不了解认证和发送 REST 请求等实现细节的情况下获取档案。

客户端仅通过接口与集合和迭代器交互, 也就不会同具体类耦合。 如果你决定将应用连接到全新的社交网络, 只需提供新的集合和迭代器类即可, 无需修改现有代码。

// 集合接口必须声明一个用于生成迭代器的工厂方法。如果程序中有不同类型的迭
// 代器,你也可以声明多个方法。
interface SocialNetwork is
    method createFriendsIterator(profileId):ProfileIterator
    method createCoworkersIterator(profileId):ProfileIterator


// 每个具体集合都与其返回的一组具体迭代器相耦合。但客户并不是这样的,因为
// 这些方法的签名将会返回迭代器接口。
class WeChat implements SocialNetwork is
    // ...大量的集合代码应该放在这里...

    // 迭代器创建代码。
    method createFriendsIterator(profileId) is
        return new WeChatIterator(this, profileId, "friends")
    method createCoworkersIterator(profileId) is
        return new WeChatIterator(this, profileId, "coworkers")


// 所有迭代器的通用接口。
interface ProfileIterator is
    method getNext():Profile
    method hasMore():bool


// 具体迭代器类。
class WeChatIterator implements ProfileIterator is
    // 迭代器需要一个指向其遍历集合的引用。
    private field weChat: WeChat
    private field profileId, type: string

    // 迭代器对象会独立于其他迭代器来对集合进行遍历。因此它必须保存迭代器
    // 的状态。
    private field currentPosition
    private field cache: array of Profile

    constructor WeChatIterator(weChat, profileId, type) is
        this.weChat = weChat
        this.profileId = profileId
        this.type = type

    private method lazyInit() is
        if (cache == null)
            cache = weChat.socialGraphRequest(profileId, type)

    // 每个具体迭代器类都会自行实现通用迭代器接口。
    method getNext() is
        if (hasMore())
            currentPosition++
            return cache[currentPosition]

    method hasMore() is
        lazyInit()
        return currentPosition < cache.length


// 这里还有一个有用的绝招:你可将迭代器传递给客户端类,无需让其拥有访问整
// 个集合的权限。这样一来,你就无需将集合暴露给客户端了。
//
// 还有另一个好处:你可在运行时将不同的迭代器传递给客户端,从而改变客户端
// 与集合互动的方式。这一方法可行的原因是客户端代码并没有和具体迭代器类相
// 耦合。
class SocialSpammer is
    method send(iterator: ProfileIterator, message: string) is
        while (iterator.hasMore())
            profile = iterator.getNext()
            System.sendEmail(profile.getEmail(), message)


// 应用程序(Application)类可对集合和迭代器进行配置,然后将其传递给客户
// 端代码。
class Application is
    field network: SocialNetwork
    field spammer: SocialSpammer

    method config() is
        if working with WeChat
            this.network = new WeChat()
        if working with LinkedIn
            this.network = new LinkedIn()
        this.spammer = new SocialSpammer()

    method sendSpamToFriends(profile) is
        iterator = network.createFriendsIterator(profile.getId())
        spammer.send(iterator, "非常重要的消息")

    method sendSpamToCoworkers(profile) is
        iterator = network.createCoworkersIterator(profile.getId())
        spammer.send(iterator, "非常重要的消息")

# 与其他模式的关系

  • 你可以使用迭代器模式 (opens new window)来遍历组合模式 (opens new window)树。
  • 你可以同时使用工厂方法模式 (opens new window)和迭代器 (opens new window)来让子类集合返回不同类型的迭代器, 并使得迭代器与集合相匹配。
  • 你可以同时使用备忘录模式 (opens new window)和迭代器 (opens new window)来获取当前迭代器的状态, 并且在需要的时候进行回滚。
  • 可以同时使用访问者模式 (opens new window)和迭代器 (opens new window)来遍历复杂数据结构, 并对其中的元素执行所需操作, 即使这些元素所属的类完全不同。

# 案例

使用示例: 该模式在 Java 代码中很常见。 许多框架和程序库都会使用它来提供遍历其集合的标准方式。

下面是该模式在核心 Java 程序库中的一些示例:

  • java.util.Iterator (opens new window)的所有实现 (还有 java.util.Scanner (opens new window))。
  • java.util.Enumeration (opens new window)的所有实现

识别方法: 迭代器可以通过导航方法 (例如 next和 previous等) 来轻松识别。 使用迭代器的客户端代码可能没有其所遍历的集合的直接访问权限。

# 参考资料

  • 《Head First 设计模式》 (opens new window)
  • 《大话设计模式》 (opens new window)
  • 设计模式教程 (opens new window)
📝 帮助改善此页面! (opens new window)
#设计#设计模式
上次更新: 2024/01/27, 23:24:21
设计模式之命令模式
设计模式之观察者模式

← 设计模式之命令模式 设计模式之观察者模式→

最近更新
01
设计
04-27
02
微服务简介
04-15
03
如何设计系统
11-08
更多文章>
Theme by Vdoing | Copyright © 2019-2024 钝悟(dunwu) | CC-BY-SA-4.0
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×