程序员必知!迭代器模式的实战应用与案例分析

迭代器模式提供了遍历聚合对象中各元素的方法,通过它无需了解其底层结构,例如,在电商平台商品列表中统计销售额时,可通过迭代器简化遍历过程,加总每个商品销售额,此模式使代码更简洁、易维护,且适用于不同类型的聚合对象,实现轻松扩展。

定义

迭代器模式提供了一种遍历一个聚合对象中各个元素的方法,而不需要知道该对象的底层表示方式,它的主要目的是提供一个统一的、简洁的方式来遍历一个聚合对象的所有元素,而不需要关心该聚合对象的内部表示方式。

举一个业务中形象的例子来说明迭代器模式:假设有一个电商平台的商品列表,这个商品列表由多个商品组成,现在想要统计所有商品的销售额,可以使用迭代器模式来遍历所有商品并计算总销售额,具体来说,可以定义一个商品列表的聚合对象,然后定义一个迭代器,通过迭代器来遍历所有的商品对象,并对每个商品对象执行加总操作,最终得到所有商品的销售额,使用迭代器模式可以使得代码更加简洁、易于维护,并且可以轻松地扩展到其他类型的聚合对象。

代码案例

反例

下面是一个未使用迭代器模式的反例代码,在未使用迭代器模式的情况下,要遍历一个聚合对象(比如一个列表或集合)并对其进行操作,通常可能会直接在client代码中处理聚合对象的内部表示,这样做会导致client代码与聚合对象的内部结构紧密耦合,违反了设计模式的封装原则,如下代码:

java 复制代码
import java.util.ArrayList;  
import java.util.List;  
  
// 产品类  
class Product {  
    private String name;  
    private double price;  
  
    public Product(String name, double price) {  
        this.name = name;  
        this.price = price;  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public double getPrice() {  
        return price;  
    }  
  
    @Override  
    public String toString() {  
        return "Product{" +  
                "name='" + name + '\'' +  
                ", price=" + price +  
                '}';  
    }  
}  
  
// 产品目录类,未使用迭代器模式  
class ProductCatalog {  
    // 内部使用ArrayList存储产品  
    private List<Product> products = new ArrayList<>();  
  
    // 直接暴露内部列表,违反封装原则  
    public List<Product> getProducts() {  
        return products;  
    }  
  
    public void addProduct(Product product) {  
        products.add(product);  
    }  
}  
  
// 客户端代码  
public class Client {  
    public static void main(String[] args) {  
        ProductCatalog catalog = new ProductCatalog();  
        catalog.addProduct(new Product("Laptop", 999.99));  
        catalog.addProduct(new Product("Smartphone", 499.99));  
        catalog.addProduct(new Product("Tablet", 299.99));  
  
        // 客户端直接操作ProductCatalog的内部结构  
        for (Product product : catalog.getProducts()) {  
            System.out.println(product);  
        }  
  
        // 假设我们需要修改ProductCatalog的内部实现,比如使用LinkedList替代ArrayList  
        // 那么客户端代码也需要相应地进行修改,这违反了开闭原则  
    }  
}	

运行上面的代码会得到以下输出:

ini 复制代码
Product{name='Laptop', price=999.99}  
Product{name='Smartphone', price=499.99}  
Product{name='Tablet', price=299.99}

在这个例子中,ProductCatalog类直接暴露了它的内部列表products,client代码通过getProducts方法直接访问这个列表并进行遍历,这样做的问题是,如果ProductCatalog的内部实现发生变化(比如从ArrayList换成LinkedList),client代码也需要相应地进行修改,因为client代码已经与ProductCatalog的内部实现紧密耦合在一起了。

为了避免这种紧密耦合,应该使用迭代器模式来提供一个统一的遍历接口,从而隐藏聚合对象的内部表示,这样,即使聚合对象的内部实现发生变化,client代码也不需要修改,因为它只依赖于迭代器接口。

正例

下面是一个使用迭代器模式的正例代码,创建一个迭代器接口来定义遍历元素所需的方法,然后为聚合对象创建一个类来实现这个接口,这样做的好处是client代码可以只依赖于迭代器接口,而不是聚合对象的具体实现,从而实现了松耦合,如下代码:

java 复制代码
import java.util.ArrayList;  
import java.util.Iterator;  
import java.util.List;  
  
// 产品类  
class Product {  
    private String name;  
    private double price;  
  
    public Product(String name, double price) {  
        this.name = name;  
        this.price = price;  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public double getPrice() {  
        return price;  
    }  
  
    @Override  
    public String toString() {  
        return "Product{" +  
                "name='" + name + '\'' +  
                ", price=" + price +  
                '}';  
    }  
}  
  
// 迭代器接口  
interface Iterator<T> {  
    boolean hasNext();  
    T next();  
}  
  
// 产品目录类,使用了迭代器模式  
class ProductCatalog implements Iterable<Product> {  
    // 内部使用ArrayList存储产品  
    private List<Product> products = new ArrayList<>();  
  
    public void addProduct(Product product) {  
        products.add(product);  
    }  
  
    // 创建并返回产品迭代器  
    @Override  
    public Iterator<Product> iterator() {  
        return new ProductIterator(products);  
    }  
  
    // 私有内部类实现迭代器接口  
    private class ProductIterator implements Iterator<Product> {  
        private List<Product> productList;  
        private int position;  
  
        public ProductIterator(List<Product> productList) {  
            this.productList = productList;  
        }  
  
        @Override  
        public boolean hasNext() {  
            return position < productList.size();  
        }  
  
        @Override  
        public Product next() {  
            if (hasNext()) {  
                return productList.get(position++);  
            } else {  
                return null; // 或者抛出异常  
            }  
        }  
    }  
}  
  
// 客户端代码  
public class Client {  
    public static void main(String[] args) {  
        ProductCatalog catalog = new ProductCatalog();  
        catalog.addProduct(new Product("Laptop", 999.99));  
        catalog.addProduct(new Product("Smartphone", 499.99));  
        catalog.addProduct(new Product("Tablet", 299.99));  
  
        // 使用迭代器遍历产品目录  
        for (Product product : catalog) {  
            System.out.println(product);  
        }  
  
        // 客户端代码不依赖于ProductCatalog的内部实现,  
        // 如果内部实现发生变化,客户端代码不需要修改。  
    }  
}

运行上面的代码会得到以下输出:

java 复制代码
Product{name='Laptop', price=999.99}  
Product{name='Smartphone', price=499.99}  
Product{name='Tablet', price=299.99}

在这个例子中,ProductCatalog类实现了Iterable接口,并提供了一个iterator方法来创建并返回ProductIterator对象,ProductIteratorProductCatalog的一个私有内部类,它实现了Iterator接口来遍历产品列表,client代码使用增强的for循环(它内部使用了迭代器)来遍历ProductCatalog中的产品,而不需要知道其内部是如何存储产品的。

这个实现遵循了迭代器模式,允许client代码以统一的方式遍历聚合对象,而不需要了解聚合对象的内部表示,使得client代码与聚合对象之间实现了松耦合,符合开闭原则。

核心总结

迭代器模式是一种常用的设计模式,它使程序能够遍历聚合对象的元素而无需暴露其内部表示,它支持对聚合对象的多种遍历,简化了聚合类,符合单一职责原则,使client代码与聚合对象的具体实现解耦,增强了系统的可扩展性,当需要新增遍历方式时,只需增加新的迭代器类,不影响原有代码;迭代器模式会涉及到较多的类,可能会增加系统的复杂性和开发成本,同时,由于它将存储数据和遍历数据的职分离,可能在某些情况下导致额外的性能开销,在需要遍历复杂数据结构或支持多种遍历方式时,推荐使用迭代器模式,但要注意权衡系统复杂性和灵活性,避免过度设计,同时,可以考虑使用Java内置的迭代器接口和工具类来简化实现。

相关推荐
小陈工14 分钟前
2026年3月28日技术资讯洞察:5G-A边缘计算落地、低延迟AI推理革命与工业智造新范式
开发语言·人工智能·后端·python·5g·安全·边缘计算
azhou的代码园1 小时前
基于SpringBoot+微信小程序的图片识别科普系统
spring boot·后端·微信小程序
Tony Bai1 小时前
Rust 看了流泪,AI 看了沉默:扒开 Go 泛型最让你抓狂的“残疾”类型推断
开发语言·人工智能·后端·golang·rust
用户3167361303422 小时前
javaLangchain4j从官方文档入手,看他做了什么——具体使用(二)
后端
無名路人2 小时前
Zsh 脚本 + VS Code 任务:NestJS + Vue3 一键部署到 1Panel
运维·后端·自动化运维
BPM6662 小时前
从 Activiti 到流程平台:企业流程架构升级实践总结
架构·自动化·敏捷流程
晏宁科技YaningAI2 小时前
全球短信路由系统设计逻辑打破 80%送达率瓶颈:工程实践拆解
网络·网络协议·架构·gateway·信息与通信·paas
ybwycx2 小时前
springboot之集成Elasticsearch
spring boot·后端·elasticsearch
程途知微3 小时前
AQS 同步器——Java 并发框架的核心底座全解析
java·后端
iPadiPhone3 小时前
分布式架构的“润滑剂”:RabbitMQ 核心原理与大厂面试避坑指南
分布式·后端·面试·架构·rabbitmq