设计模式之迭代器模式

设计模式之迭代器模式

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

这里我们认为集合(或者称容器)的作用是用于存储数据,而遍历元素这个事情与存储元素应该分开,

以满足开闭原则、单一职责原则。Java集合框架就大量使用了迭代器模式

看一眼类图:

image-20201124234506743

举个例子吧:

假设我们现在有一组无线收音机频道列表,我们想一个频道一个频道的去切换,找我们喜欢的东西。当然,有些人可能只听英语的频道,然后再做决定。

如何编写程序呢?

我们需要一个频道的集合,然后客户端去写程序遍历频道,然后决定下一步怎么做。这个方案好么?

并不好,这样客户端就必须知道遍历的逻辑,客户端也不能保证他写的遍历逻辑就是对的。另外,如果客户的数据量长,它就将变得难以维护。

这时候就适合使用迭代器模式,我们需要保证,客户端只能通过迭代器去遍历集合。

首先定义频道类型

public enum ChannelTypeEnum {

	ENGLISH, HINDI, FRENCH, ALL;
}

接下来就是频道了:

/**
* 简单简单的POJO,有频率和类型两个属性
*/
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;
	}
	
}

定义一个集合类:

public interface ChannelCollection {

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

注意:为了不让客户端能直接操作我们的集合,这里有添加频道、移除频道但没有方法返回频道列表

还有个获取迭代器方法,客户端都统一用这个方法,获取迭代器,然后利用迭代器来 遍历集合。

迭代器接口:

public interface ChannelIterator {

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

集合实现类:

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;
		}

	}
}

迭代器实现类放在里面,用内部类是因为内部类能访问外部类的全部属性,而且也就不能被其他集合使用了。毕竟专属于这个集合的遍历逻辑,也不一定适用其他类型的集合。

你主要稍微注意下java中的集合框架,你会发现也是这么做的,比如ArrayList。

Client:

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 Type Iterator
		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

小结一下吧:

基本不怎么用,因为java中你需要用到集合的地方迭代器都给你定义 好了,不过我们得能看出它的设计模式啊,

posted @ 2020-11-25 00:07  HeliusKing  阅读(148)  评论(0编辑  收藏  举报