Java 中的迭代器设计模式

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

迭代器设计模式

根据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("******");
		// 頻道類型遍歷器
		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 中的 Iterator 設計模式

我們都知道 Collection 框架的 Iterator 是迭代器模式實現的最佳例子,但您是否知道 java.util.Scanner 類也實現了 Iterator 接口。閱讀此文章了解 Java Scanner 類。這就是迭代器設計模式的全部內容,希望對您有所幫助,並且容易理解。

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