• 设计模式之迭代器模式


    设计模式之迭代器模式

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

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

    以满足开闭原则、单一职责原则。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中你需要用到集合的地方迭代器都给你定义 好了,不过我们得能看出它的设计模式啊,

  • 相关阅读:
    Ubuntu 12.04 git server
    Moonlight不再继续?!
    Orchard 视频资料
    一恍惚八月最后一天了
    Box2D lua binding and Usage
    50岁还在编程,也可以是一种成功
    DAC 4.2 发布
    再次祝贺OpenStack私有云搭建成功
    vue项目快速搭建
    pdf.js使用详解
  • 原文地址:https://www.cnblogs.com/heliusKing/p/14033632.html
Copyright © 2020-2023  润新知