重学设计模式(三设计模式-迭代器模式)

Posted 穆瑾轩

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重学设计模式(三设计模式-迭代器模式)相关的知识,希望对你有一定的参考价值。

1、迭代器模式

    从JDK1.2开始,引入了一个Iterator接口:

public interface Iterator<E> 
    boolean hasNext();
    E next();
    void remove();

    所有实现了Iterator接口的都包含一个Iterator<E> iterator()方法,它使得调用者并不知道迭代的对象具体由哪个类来实例化的。

    迭代器(Iterator)在Java集合中被广泛使用,这我们应该比较熟悉了,它提供了用于顺序访问容器中的各个元素的方法。这就是我们今天要学习的迭代器模式。

1.1、什么是迭代器模式

  • 定义

    迭代器模式是一种行为设计模式,提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示(列表、堆栈、树...)的情况下遍历集合的元素。

    迭代器模式不仅仅是遍历一个集合,我们可以根据我们的需求提供不同类型的迭代器。不过我们很少会自己实现一个迭代器,java API中提供的迭代器完全够用了。

迭代器的结构:

    1)抽象聚合(Aggregate)角色:定义存储、添加、删除聚合对象以及创建迭代器对象的接口;

    2)具体聚合(ConcreteAggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例;

    3)抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、first()、next() 等方法;

    4)实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。

    迭代器模式的意图在于:提供一种在不暴露其底层表示的情况下访问聚合对象的元素的方法。

1.2、迭代器模式的优缺点

  • 优点

    1)符合单一职责原则,可以将庞大的遍历算法提取到单独的类中来清理客户端代码和集合。

    2)符合开闭原则,可以根据我们自己的需求实现新类型的集合和迭代器,无须修改原有代码。

    3)具有封装性良好,为遍历不同的聚合结构提供一个统一的接口。

  • 缺点

    1)如果是比较简单的集合,使用迭代器模式可能是一种矫枉过正的做法;

    2)使用迭代器可能比直接遍历某些专门集合的元素效率低。

1.3、创建方式

    我们以电视频道为例,写一个自定义的迭代器。

1)新建一个Channel的POJO类(Plain Ordinary Java Object-简单java对象)

//先声明我们的频道枚举
public enum ChannelTypeEnum 

	CCTV1, CCTV2, CCTV3, JXTV1, JXTV2 ,ALL;


//Channel是一个简单的 POJO 类,包含频道号码和频道
public class Channel 

	private Integer number;
	
	private ChannelTypeEnum TYPE;
	
	public Channel(Integer number,ChannelTypeEnum TYPE)
		this.number = number;
		this.TYPE = TYPE;
	

	public Integer getNumber() 
		return number;
	

	public void setNumber(Integer number) 
		this.number = number;
	

	public ChannelTypeEnum getTYPE() 
		return TYPE;
	

	public void setTYPE(ChannelTypeEnum tYPE) 
		TYPE = tYPE;
	

	@Override
	public String toString() 
		return this.number+"频道是"+this.TYPE;
	
	

2)抽象迭代器(Iterator)角色

public interface ChannelIterator 

	//判断是否还有元素
	public boolean hasNext();
	
	//下个元素
	public Channel next();
	
	//是否是最后一个
	public boolean isLast();

3)抽象聚合(Aggregate)角色

public interface ChannelCollection 

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

4)具体聚合(ConcreteAggregate)角色

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 cursor; //定义游标

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

		@Override
		public boolean hasNext() 
			//通过比较大小来实现
			while (cursor < channels.size()) 
				Channel c = channels.get(cursor);
				if (c.getTYPE().equals(type) || type.equals(ChannelTypeEnum.ALL)) 
					return true;
				 else
					cursor++;
			
			return false;
		

		@Override
		public Channel next() 
			Channel c = channels.get(cursor);
			cursor++;
			return c;
		

		@Override
		public boolean isLast() 
			if(cursor==(channels.size()-1))
				return true;
			
			return false;
		
	

5)客户端

public class Client 

	public static void main(String[] args) 
		//新建集合,并添加频道(1-6频道)
		ChannelCollection channels = new ChannelCollectionImpl();
		channels.addChannel(new Channel(1,ChannelTypeEnum.CCTV1));
		channels.addChannel(new Channel(2,ChannelTypeEnum.CCTV2));
		channels.addChannel(new Channel(3,ChannelTypeEnum.CCTV3));
		channels.addChannel(new Channel(4,ChannelTypeEnum.JXTV1));
		channels.addChannel(new Channel(5,ChannelTypeEnum.JXTV2));
		channels.addChannel(new Channel(6,ChannelTypeEnum.JXTV2));
		
		//遍历所有频道
		ChannelIterator iterator = channels.iterator(ChannelTypeEnum.ALL);
		while(iterator.hasNext())
			Channel channel = iterator.next();
			System.out.println(channel.toString());
			if(iterator.isLast())
				System.out.println("我是最后一个了---------------");
			
		
		
		System.out.println("遍历指定的频道---------------");
		//发现有两个JXTV1,只遍历JXTV2
		ChannelIterator jxtv1 = channels.iterator(ChannelTypeEnum.JXTV2);
		while(jxtv1.hasNext())
			Channel channel = jxtv1.next();
			System.out.println(channel.toString());
		
		
	
	

案例效果:

1.4、总结及建议

    迭代器模式是通过将聚合对象的遍历行为分离出来,抽象成迭代器类来实现的,其目的是在不暴露聚合对象的内部结构的情况下,让外部代码透明地访问聚合的内部数据。

应用场景:

    1)如果希望提供一种标准方法来迭代集合并隐藏客户端程序的实现逻辑时,可以使用迭代器模式;

    2)当需要为遍历不同的聚合结构提供一个统一的接口时,可以使用迭代器模式。

JDK中迭代器模式的应用:

    Collection子类

    java.util.Scanner

以上是关于重学设计模式(三设计模式-迭代器模式)的主要内容,如果未能解决你的问题,请参考以下文章

重学设计模式(三设计模式-访问者模式)

重学设计模式(三设计模式-访问者模式)

重学设计模式(三设计模式-装饰器模式)

设计模式---迭代器模式

重学设计模式(三设计模式-适配器模式)

重学设计模式(三设计模式-备忘录模式)