迭代器模式,存储数据与遍历数据的分离

2022-05-05  本文已影响0人  程就人生

你是否每次要遍历一个集合时,总是若有所思?

集合的遍历,是怎么迭代的来?有没有通用法则?

你有没有想过,自己来实现一个迭代器?



迭代器模式(Iterator Pattern),是一种顺序访问聚合对象的行为型模式,它把存储数据和遍历数据进行了解耦。使用户不必关心集合对象的底层表示,即可顺序地访问集合中的对象。

业务场景:需要把存储数据和遍历数据分开处理的场合。

关键代码:hasNext和next;hasNext表示还有没有下一个对象;next则表示访问下一个对象。

下面看UML类图:


UML类图说明:IIterator负责数据遍历,IContainer负责数据存储,NameRepository又聚合了NameIterator,关系非常简单。

代码实现步骤:

  1. 迭代器接口;
/**
 * 1.遍历接口
 * @author 程就人生
 * @Date
 */
public interface IIterator<T> {
  // 还有没有下一个元素
  public boolean hasNext();
  // 读取下一个元素
  public T next();
}

2.容器接口;

/**
 * 2.容器接口
 * @author 程就人生
 * @Date
 */
public interface IContainer<T> {
  // 迭代集合中所有的元素
  public IIterator<T> getIterator();
}

3.容器实现类;

import java.util.ArrayList;
import java.util.List;

/**
 * 3.容器实现类
 * @author 程就人生
 * @Date
 */
public class NameRepository implements IContainer<String>{
  
  private List<String> nameList;
  
  public NameRepository(){
    nameList = new ArrayList<String>();
  }
  
  public void add(String name){
    nameList.add(name);
  }

  @Override
  public IIterator<String> getIterator() {
    return new NameIterator(nameList);
  }
}

4.迭代器实现类;

import java.util.List;

/**
 * 4. 遍历数据的具体实现
 * @author 程就人生
 * @Date
 */
public class NameIterator implements IIterator<String>{
  
  private int index;
  
  private List<String> nameList;
  
  public NameIterator(List<String> nameList){
    this.nameList =nameList;
  }

  @Override
  public boolean hasNext() {
    // 有则返回true,否则返回false
    if(nameList != null && index < nameList.size()){
      return true;
    }
    return false;
  }

  @Override
  public String next() {
    if(this.hasNext()){
      return nameList.get(index++);
    }
    return null;
  }  
}

也可以把迭代器作为容器实现类的内部类来实现;

import java.util.ArrayList;
import java.util.List;

/**
 * 3.NameRepository实现了容器接口
 * @author 程就人生
 * @Date
 */
public class NameRepository implements IContainer<String>{
  private static List<String> nameList;
  public NameRepository(){
    nameList = new ArrayList<String>();
  }
  
  public void add(String name){
    nameList.add(name);
  }
  
  @Override
  public IIterator<String> getIterator() {
    return new NameIterator();
  }
  
  /**
   * 3.1 内部类实现了遍历接口,遍历数据的具体实现
   * @author 程就人生
   * @Date
   */
  private class NameIterator implements IIterator<String>{    
    private int index;
    @Override
    public boolean hasNext() {
      if(nameList != null && index < nameList.size()){
        return true;
      }
      return false;
    }
    @Override
    public String next() {
      if(this.hasNext()){
        return nameList.get(index++);
      }
      return null;
    }    
  }
}

5.测试代码;

public static void main(String[] argo){ 
    NameRepository nameRepository = new NameRepository();
    // 数据存储
    nameRepository.add("张三");
    nameRepository.add("王五");
    nameRepository.add("李四");
    
    // 数据遍历,存在下一个时,则打印下一个对象    
    for(IIterator<String> iterator = nameRepository.getIterator(); iterator.hasNext();){
      System.out.println(iterator.next());
    }
  }
}

测试结果:

张三
王五
李四

这段代码的意思是:创建一个动态存储名称的容器NameRepository,其中NameIterator类通过hasNext判断是否还有下一个元素,通过Next获取下一个元素,如此循环,直至把聚合对象中的元素全部遍历完毕。

NameIterator即可作为一个单独的类处理,又可聚合到NameRepository对象里面,作为该对象的内部类使用。至此,一个简单的迭代器模式编码完成。

最后总结

迭代器模式,主要负责存储数据和遍历数据的分离。它是一种很好理解,又经常使用的行为型模式。

思考题:列举一下在项目中,各种集合的遍历是如何实现的吧!

上一篇下一篇

猜你喜欢

热点阅读