Java中的迭代器设计模式

迭代器设计模式是行为模式之一。迭代器模式用于提供一种标准方式遍历一组对象。迭代器模式在Java集合框架中被广泛使用。迭代器接口提供了遍历集合的方法。

迭代器设计模式

根据GoF,迭代器设计模式的意图是:

提供一种访问聚合对象元素的方式,而不暴露其底层表示。

迭代器模式不仅仅是关于遍历集合,我们可以根据需求提供不同类型的迭代器。迭代器设计模式隐藏了通过集合进行遍历的实际实现,客户端程序只是使用迭代器方法。

迭代器模式示例

让我们通过一个简单的例子来了解迭代器模式。假设我们有一个无线电频道的列表,客户端程序想要逐个遍历它们,或者根据频道类型遍历它们。例如,有些客户端程序只对英语频道感兴趣,希望仅处理它们,而不处理其他类型的频道。因此,我们可以向客户端提供一个频道集合,并让他们编写逻辑来遍历频道并决定是否处理它们。但是,这种解决方案有很多问题,比如客户端必须提出遍历的逻辑。我们不能确保客户端逻辑是正确的。而且,如果客户端的数量增加,维护将变得非常困难。在这里,我们可以使用迭代器模式,并根据频道类型提供迭代。我们应该确保客户端程序只能通过迭代器访问频道列表。实施的第一部分是为我们的集合和迭代器接口定义契约。 ChannelTypeEnum.java

package com.journaldev.design.iterator;

public enum ChannelTypeEnum {

	ENGLISH, HINDI, FRENCH, ALL;
}

ChannelTypeEnum是java枚举,定义了所有不同类型的频道。 Channel.java

package com.journaldev.design.iterator;

public class Channel {

	private double frequency;
	private ChannelTypeEnum TYPE;
	
	public Channel(double freq, ChannelTypeEnum type){
		this.frequency=freq;
		this.TYPE=type;
	}

	public double getFrequency() {
		return frequency;
	}

	public ChannelTypeEnum getTYPE() {
		return TYPE;
	}
	
	@Override
	public String toString(){
		return "Frequency="+this.frequency+", Type="+this.TYPE;
	}
	
}

Channel是一个简单的POJO类,具有频率和频道类型两个属性。 ChannelCollection.java

package com.journaldev.design.iterator;

public interface ChannelCollection {

	public void addChannel(Channel c);
	
	public void removeChannel(Channel c);
	
	public ChannelIterator iterator(ChannelTypeEnum type);
	
}

ChannelCollection 接口定义了我们集合类实现的契约。请注意,有添加和移除频道的方法,但没有返回频道列表的方法。ChannelCollection 有一个返回遍历的迭代器的方法。ChannelIterator 接口定义了以下方法;ChannelIterator.java

package com.journaldev.design.iterator;

public interface ChannelIterator {

	public boolean hasNext();
	
	public Channel next();
}

现在我们的基础接口和核心类已经准备好,让我们继续实现集合类和迭代器。ChannelCollectionImpl.java

package com.journaldev.design.iterator;

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

public class ChannelCollectionImpl implements ChannelCollection {

	private List<Channel> channelsList;

	public ChannelCollectionImpl() {
		channelsList = new ArrayList<>();
	}

	public void addChannel(Channel c) {
		this.channelsList.add(c);
	}

	public void removeChannel(Channel c) {
		this.channelsList.remove(c);
	}

	@Override
	public ChannelIterator iterator(ChannelTypeEnum type) {
		return new ChannelIteratorImpl(type, this.channelsList);
	}

	private class ChannelIteratorImpl implements ChannelIterator {

		private ChannelTypeEnum type;
		private List<Channel> channels;
		private int position;

		public ChannelIteratorImpl(ChannelTypeEnum ty,
				List<Channel> channelsList) {
			this.type = ty;
			this.channels = channelsList;
		}

		@Override
		public boolean hasNext() {
			while (position < channels.size()) {
				Channel c = channels.get(position);
				if (c.getTYPE().equals(type) || type.equals(ChannelTypeEnum.ALL)) {
					return true;
				} else
					position++;
			}
			return false;
		}

		@Override
		public Channel next() {
			Channel c = channels.get(position);
			position++;
			return c;
		}

	}
}

注意内部类实现了迭代器接口,以便该实现不能被任何其他集合使用。集合类也采用相同的方法,它们都有迭代器接口的内部类实现。让我们编写一个简单的迭代器模式测试程序,使用我们的集合和迭代器遍历频道的集合。IteratorPatternTest.java

package com.journaldev.design.iterator;

public class IteratorPatternTest {

	public static void main(String[] args) {
		ChannelCollection channels = populateChannels();
		ChannelIterator baseIterator = channels.iterator(ChannelTypeEnum.ALL);
		while (baseIterator.hasNext()) {
			Channel c = baseIterator.next();
			System.out.println(c.toString());
		}
		System.out.println("******");
		// Channel 类型的迭代器
		ChannelIterator englishIterator = channels.iterator(ChannelTypeEnum.ENGLISH);
		while (englishIterator.hasNext()) {
			Channel c = englishIterator.next();
			System.out.println(c.toString());
		}
	}

	private static ChannelCollection populateChannels() {
		ChannelCollection channels = new ChannelCollectionImpl();
		channels.addChannel(new Channel(98.5, ChannelTypeEnum.ENGLISH));
		channels.addChannel(new Channel(99.5, ChannelTypeEnum.HINDI));
		channels.addChannel(new Channel(100.5, ChannelTypeEnum.FRENCH));
		channels.addChannel(new Channel(101.5, ChannelTypeEnum.ENGLISH));
		channels.addChannel(new Channel(102.5, ChannelTypeEnum.HINDI));
		channels.addChannel(new Channel(103.5, ChannelTypeEnum.FRENCH));
		channels.addChannel(new Channel(104.5, ChannelTypeEnum.ENGLISH));
		channels.addChannel(new Channel(105.5, ChannelTypeEnum.HINDI));
		channels.addChannel(new Channel(106.5, ChannelTypeEnum.FRENCH));
		return channels;
	}

}

当我运行上面的程序时,它产生以下输出:

Frequency=98.5, Type=ENGLISH
Frequency=99.5, Type=HINDI
Frequency=100.5, Type=FRENCH
Frequency=101.5, Type=ENGLISH
Frequency=102.5, Type=HINDI
Frequency=103.5, Type=FRENCH
Frequency=104.5, Type=ENGLISH
Frequency=105.5, Type=HINDI
Frequency=106.5, Type=FRENCH
******
Frequency=98.5, Type=ENGLISH
Frequency=101.5, Type=ENGLISH
Frequency=104.5, Type=ENGLISH

迭代器设计模式重要点

  • 迭代器模式在您希望提供在集合上进行迭代的标准方式并将实现逻辑隐藏在客户端程序中时非常有用。
  • 迭代的逻辑嵌入在集合本身中,并且它有助于客户端程序轻松地对它们进行迭代。

JDK中的迭代器设计模式

我们都知道集合框架的迭代器是迭代器模式实现的最佳例子,但您知道java.util.Scanner类也实现了迭代器接口吗?阅读本文了解Java Scanner类。关于迭代器设计模式的介绍就到这里,希望对您有所帮助,易于理解。

Source:
https://www.digitalocean.com/community/tutorials/iterator-design-pattern-java