设计模式——迭代器模式



  

1 初识迭代器模式:

定义:提供一种方法来顺序访问一个集合对象中的各个元素,而又不需要暴露该对象的内部表示

结构:



 

 注意:  具体集合是放在迭代器实现类内,作为属性和迭代器实现关联, 具体集合仅仅作为一个数据集的作用,迭代器则对数据如何取,内部增加什么过滤或者算法,来实现对具体集合数据的操作,

你可以理解 集合是原木, 迭代器是木匠,木匠可以通过自己的手法(算法)来对原木进行全部获取或者雕刻成什么作品来部分获取

参考实现:

    迭代器模式调用流程图:

 

使用数组作为基础集合数据来模拟迭代器代码部分:


 

客户端:
public class Client {
	public void someOperation(){
		String[] names = {"张三","李四","王五"};
		Aggregate aggregate = new ConcreteAggregate(names);
		Iterator it = aggregate.createIterator();
		//首先设置迭代器到第一个元素
		it.first();
		while(!it.isDone()){
			Object obj = it.currentItem();
			System.out.println("the obj=="+obj);
			it.next();
		}
	}	
	public static void main(String[] args) {
		Client client = new Client();
		client.someOperation();
	}
}

集合接口:
public abstract class Aggregate {
	/**
	 * 工厂方法,创建相应迭代器对象的接口
	 * @return 相应迭代器对象的接口
	 */
	public abstract Iterator createIterator();
}

集合实现类:
public class ConcreteAggregate extends Aggregate {
	/**
	 * 示意,表示聚合对象具体的内容
	 */
	private String[] ss = null;
	
	/**
	 * 构造方法,传入聚合对象具体的内容
	 * @param ss 聚合对象具体的内容
	 */
	public ConcreteAggregate(String[] ss){
		this.ss = ss;
	}
	
	public Iterator createIterator() {
		//实现创建Iterator的工厂方法
		return new ConcreteIterator(this);
	}
	/**
	 * 获取索引所对应的元素
	 * @param index 索引
	 * @return 索引所对应的元素
	 */
	public Object get(int index){
		Object retObj = null;
		if(index < ss.length){
			retObj = ss[index];
		}
		return retObj;
	}
	/**
	 * 获取聚合对象的大小
	 * @return 聚合对象的大小
	 */
	public int size(){
		return this.ss.length;
	}
}

迭代器接口:
public interface Iterator {
	/**
	 * 移动到聚合对象的第一个位置
	 */
	public void first();
	/**
	 * 移动到聚合对象的下一个位置
	 */
	public void next();
	/**
	 * 判断是否已经移动聚合对象的最后一个位置
	 * @return true表示已经移动到聚合对象的最后一个位置,
	 *         false表示还没有移动到聚合对象的最后一个位置
	 */
	public boolean isDone();
	/**
	 * 获取迭代的当前元素
	 * @return 迭代的当前元素
	 */
	public Object currentItem();
}

迭代器实现类:
public class ConcreteIterator implements Iterator {
	/**
	 * 持有被迭代的具体的聚合对象
	 */
	private ConcreteAggregate aggregate;
	/**
	 * 内部索引,记录当前迭代到的索引位置。
	 * -1表示刚开始的时候,迭代器指向聚合对象第一个对象之前
	 */
	private int index = -1;
	/**
	 * 构造方法,传入被迭代的具体的聚合对象
	 * @param aggregate 被迭代的具体的聚合对象
	 */
	public ConcreteIterator(ConcreteAggregate aggregate) {
		this.aggregate = aggregate;
	}

	public void first(){
		index = 0;
	}
	public void next(){
		if(index < this.aggregate.size()){
			index = index + 1;
		}
	}
	public boolean isDone(){
		if(index == this.aggregate.size()){
			return true;
		}
		return false;
	}
	public Object currentItem(){
		return this.aggregate.get(index);
	}
}

2 体会迭代器模式:

场景问题: 以一个统一方式来访问内部实现不同的聚合对象(子母公司合作统计工资模块案例)



 

不使用模式的解决方案: 代码重写,统一成同样实现方式

使用模式的解决方案: 如上图,不同模块因为使用不同具体实现,使用迭代器模式,将原来两个不同的数据

最后用相同的输出框架给框起来。达到统一输出的目的;

下面案例调用流程 请参看: 上面的 <迭代器模式调用流程图>  唯一的区别就是:

集合实现类 变成了两个,一个是PayManager, 一个是SalaryManager:

代码如下: 使用迭代器模式 给不同具体实现套上不同壳子,壳子里面是每个具体实现的具体写法,但是暴露给客户端的 将是同样的壳子

不使用迭代器模式下 客户端调用写法,次写法无法将工资输出统一起来:
public class Client {
	public static void main(String[] args) {
		//访问集团的工资列表
		PayManager payManager= new PayManager();
		//先计算再获取
		payManager.calcPay();
		Collection payList = payManager.getPayList();
		Iterator it = payList.iterator();
		System.out.println("集团工资列表:");
		while(it.hasNext()){
			PayModel pm = (PayModel)it.next();
			System.out.println(pm);
		}
		
		//访问新收购公司的工资列表
		SalaryManager salaryManager = new SalaryManager();
		//先计算再获取
		salaryManager.calcSalary();
		PayModel[] pms = salaryManager.getPays();
		System.out.println("新收购的公司工资列表:");
		for(int i=0;i<pms.length;i++){
			System.out.println(pms[i]);
		}
	}
}

使用迭代器模式下 客户端写法:

public class Client {
	public static void main(String[] args) {
		//访问集团的工资列表
		PayManager payManager= new PayManager();
		//先计算再获取
		payManager.calcPay();
		System.out.println("集团工资列表:");
		test(payManager.createIterator());
		
		//访问新收购公司的工资列表
		SalaryManager salaryManager = new SalaryManager();
		//先计算再获取
		salaryManager.calcSalary();
		System.out.println("新收购的公司工资列表:");
		test(salaryManager.createIterator());
	}
	private static void test(Iterator it){
		it.first();
		while(!it.isDone()){
			Object obj = it.currentItem();
			System.out.println("the obj=="+obj);
			it.next();
		}
	}
}

迭代器接口:
public interface Iterator {
	
	public void first();
	
	public void next();
	
	public boolean isDone();
	
	public Object currentItem();
}

迭代器实现类之针对数组:
public class ArrayIteratorImpl implements Iterator{
	/**
	 * 用来存放被迭代的聚合对象
	 */
	private SalaryManager aggregate = null;

	private int index = -1;
	
	public ArrayIteratorImpl(SalaryManager aggregate){
		this.aggregate = aggregate;
	}
	
	
	public void first(){
		index = 0;
	}
	public void next(){
		if(index < this.aggregate.size()){
			index = index + 1;
		}
	}
	public boolean isDone(){
		if(index == this.aggregate.size()){
			return true;
		}
		return false;
	}
	public Object currentItem(){
		return this.aggregate.get(index);
	}
}


迭代器实现类之针对 集合:

public class CollectionIteratorImpl implements Iterator{
	/**
	 * 用来存放被迭代的聚合对象
	 */
	private PayManager aggregate = null;
	
	private int index = -1;
	
	public CollectionIteratorImpl(PayManager aggregate){
		this.aggregate = aggregate;
	}
	
	public void first(){
		index = 0;
	}
	public void next(){
		if(index < this.aggregate.size()){
			index = index + 1;
		}
	}
	public boolean isDone(){
		if(index == this.aggregate.size()){
			return true;
		}
		return false;
	}
	public Object currentItem(){
		return this.aggregate.get(index);
	}
}

数据集合接口:
public abstract class Aggregate {
	/**
	 * 工厂方法,创建相应迭代器对象的接口
	 * @return 相应迭代器对象的接口
	 */
	public abstract Iterator createIterator();
}

数据集合实现类之针对 集合:
public class PayManager extends Aggregate{
	/**
	 * 聚合对象,这里是Java的集合对象
	 */
	private List list = new ArrayList();
	public List getPayList(){
		return list;
	}
	public void calcPay(){
		PayModel pm1 = new PayModel();
		pm1.setPay(3800);
		pm1.setUserName("张三");
		
		PayModel pm2 = new PayModel();
		pm2.setPay(5800);
		pm2.setUserName("李四");
		
		list.add(pm1);
		list.add(pm2);
	}
	
	public Iterator createIterator(){
		return new CollectionIteratorImpl(this);
	}
	public Object get(int index){
		Object retObj = null;
		if(index < this.list.size()){
			retObj = this.list.get(index);
		}
		return retObj;
	}
	public int size(){
		return this.list.size();
	}
}

迭代器实现类之针对数组:
public class SalaryManager extends Aggregate{
	/**
	 * 用数组管理
	 */
	private PayModel[] pms = null;
	public PayModel[] getPays(){
		return pms;
	}
	public void calcSalary(){
		//计算工资,并把工资信息填充到工资列表里面
		//为了测试,做点假数据进去
		PayModel pm1 = new PayModel();
		pm1.setPay(2200);
		pm1.setUserName("王五");
		
		PayModel pm2 = new PayModel();
		pm2.setPay(3600);
		pm2.setUserName("赵六");
		
		pms = new PayModel[2];
		pms[0] = pm1;
		pms[1] = pm2;
	}
	
	public Iterator createIterator(){
		return new ArrayIteratorImpl(this);
	}
	public Object get(int index){
		Object retObj = null;
		if(index < pms.length){
			retObj = pms[index];
		}
		return retObj;
	}
	public int size(){
		return this.pms.length;
	}
}

PayModel:
public class PayModel {
	/**
	 * 支付工资的人员
	 */
	private String userName;
	/**
	 * 支付的工资数额
	 */
	private double pay;
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public double getPay() {
		return pay;
	}
	public void setPay(double pay) {
		this.pay = pay;
	}
	public String toString(){
		return "userName="+userName+",pay="+pay;
	}
}

3 理解迭代器模式:

 迭代器的关键思想: 把聚合对象的遍历和访问从聚合对象中分离出来,放入到单独迭代器中,这样迭代器和聚合对象可以独立变化和发展,提高系统灵活性;

 使用Java迭代器:使用javase提供的Iterator 取代我们自定义类Iterator, 其余不变

带迭代策略的迭代器:因为迭代和访问数据的分离,因此在迭代中可以增加策略,比如 实现过滤,

  对数据进行整条过滤,只能查看自己部门的数据;

  对数据进行部分过滤,比如某人不能查看工资数据;

如下即 表示能在迭代器中增加算法  又能增加过滤功能,增加算法后新的数据集合来取代原有数据集合

public ArrayIteratorImpl(SalaryManager aggregate){
		//在这里先对聚合对象的数据进行过滤,比如工资必须在3000以下
		Collection<PayModel> tempCol = new ArrayList<PayModel>();
		for(PayModel pm : aggregate.getPays()){
			if(pm.getPay() < 3000){
				tempCol.add(pm);
			}
		}
		//然后把符合要求的数据存放到用来迭代的数组
		this.pms = new PayModel[tempCol.size()];
		int i=0;
		for(PayModel pm : tempCol){
			this.pms[i] = pm;
			i++;
		}
	}

双向迭代器:同时向前或者向后遍历数据的迭代器  eg:" java.util.ListIterator

优缺点:

4 思考迭代器模式:

本质:控制+访问 ---> 聚合对象中的元素

何时选用:

a) 访问聚合对象的同时不像暴露此对象的内部时

b) 为遍历不同聚合对象提供一个统一接口时

c) 期待以多种方式访问聚合对象时(比如 向后访问, 向前访问, 间隔一个方式访问)


 

5 迭代器脑图:



 

猜你喜欢

转载自chengjianxiaoxue.iteye.com/blog/2148024