文档章节

迭代器模式

loda0128
 loda0128
发布于 2015/05/02 01:20
字数 1843
阅读 51
收藏 0

今天来818设计模式中的迭代器模式,也是java中Stack,List,Set等接口以及数组这个数据结构都会使用的一种模式。

首先,为什么使用迭代器模式,目的就是通过一个通用的迭代方法,隐藏stack,list,set以及数组中不同的遍历细节。也就是说,我不想让那些调用我的遍历容器的方法的人知道我到底是怎么一个一个的获取这些元素的(stack的pop,list的get,数组的array[i]),我只想让他知道他能 通过一个迭代器Iterator或者通过一个for each语句就能拿到我容器里面所有的元素。这样就能够最大化的隐藏实现细节,封装变化了。

先通过一个例子来一步步了解这其中的重要性吧。比方说,我要开发一个平台,这个平台会获取到京东的订单和淘宝的订单,然后把订单中的所有购买条目全部打印出来。

既然要打印订单中的所有条目,那么就得先知道这些条目,也就是订单项有哪些属性。

package iterator;

/**
 * 
* @ClassName: Item 
* @Description: 订单项
* @author minjun
*
 */
public class Item {

	/**商品名称*/
	private String name;
	
	/**价格*/
	private double price;
	
	/**描述*/
	private String desc;
	
	/**数量*/
	private int count;

	public Item(String name, double price, String desc, int count) {
		this.name = name;
		this.price = price;
		this.desc = desc;
		this.count = count;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	public String getDesc() {
		return desc;
	}

	public void setDesc(String desc) {
		this.desc = desc;
	}

	public int getCount() {
		return count;
	}

	public void setCount(int count) {
		this.count = count;
	}

	@Override
	public String toString() {
		return "Item [name=" + name + ", price=" + price + ", desc=" + desc
				+ ", count=" + count + "]";
	}
}

知道了这个条目,然后我想看看京东和淘宝是如何存储这些条目的。于是我问了问刘强东和马云,得知京东是用集合List存储,因为方便,而淘宝是用数组存储,因为看起来更装逼。他们都不愿意修改存储的容器,因为改动太大。

这时, 如果用传统想法,ok,我拿到京东的List,然后通过for循环和list.get(i)获取里面的每个条目并打印。然后拿到淘宝的array,通过for循环和array[i]获取里面的条目并打印。是不是可以实现呢?确实可以,但是我发现这样的话,每个容器我都要实现一遍不同的打印方法。目前是两个倒还好,如果又来个谁谁谁,用链表来实现容器,那我是不是又要新加一个迭代链表的方法呢?我当然不会愿意,因为这样太麻烦了。于是乎,我有个想法,思路是这样的:

我希望让京东的订单和淘宝的订单都是可以方便的遍历里面的元素,遍历的方法能够通过一个公共的方法来处理,而不是像之前那个分别做处理。根据这个思路,用TDD(测试驱动开发)来做步骤实现。先写好测试代码,首先我要有个订单接口,里面有两个子类订单(淘宝订单和京东订单):

package iterator;

import org.junit.Test;

public class TestCase {

	@Test
	public void test() {
		Order o = 
				new TBOrder();//淘宝的订单
//				new JDOrder();//京东的订单
		printOrder(o);//打印订单

	}

	/**打印订单 */
	private void printOrder(Order o) {
		for (Item item : o) {
			System.out.println(item);
		}
	}
}



如果能像上述这样打印,那会多么方便啊。如果换成淘宝订单,就用淘宝的订单迭代实现,换成京东的订单,就用京东的订单实现,我在测试代码根本不需要关注实现细节。现在我会想,如果能通过什么方法直接打印这个订单Order中的所有条目,那才能完整的实现我上述的代码。也就是说我需要我的订单是可以遍历的,那应该怎么做呢?其实java中提供了这样的接口,就是Iterable,如果我的订单都实现了这个接口,那么我的订单自然而然就可以通过一个for each循环来遍历里面的内容。

/*
 * %W% %E%
 *
 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package java.lang;

import java.util.Iterator;

/** Implementing this interface allows an object to be the target of
 *  the "foreach" statement.
 * @since 1.5
 */
public interface Iterable<T> {

    /**
     * Returns an iterator over a set of elements of type T.
     * 
     * @return an Iterator.
     */
    Iterator<T> iterator();
}

上面是java的Iterable接口,下面是我自己的订单接口,继承了Iterable接口

package iterator;

public interface Order extends Iterable<Item>{

}

注意上面的Order订单接口继承了Iterable接口之后,同样也继承过来了一个抽象方法iterator。这个抽象方法才是Iterable的根本实现方案。我们会在子类订单中分别实现这个接口,然后提供京东和淘宝不同的迭代方案。

京东

package iterator;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 
 * @ClassName: JDOrder
 * @Description: 京东订单
 * @author minjun
 * 
 */
public class JDOrder implements Order {

	/** 京东用集合装订单项 */
	private List<Item> list = new ArrayList<Item>();

	public JDOrder() {
		add("iphone6", 5000.00, "一部手机", 2);
		add("mbp", 16000.00, "一台电脑", 1);
		add("西门子洗衣机", 3000.00, "一台洗衣机", 3);
	}

	/** 添加订单条目 */
	public void add(String name, double price, String desc, int count) {
		list.add(new Item(name, price, desc, count));
	}

	@Override
	public Iterator<Item> iterator() {
		return new MyIterator();
	}

	private class MyIterator implements Iterator<Item> {

		private Iterator<Item> it = list.iterator();

		@Override
		public boolean hasNext() {
			return it.hasNext();
		}

		@Override
		public Item next() {
			return it.next();
		}

		@Override
		public void remove() {
			throw new UnsupportedOperationException("目前不支持删除操作");
		}

	}
}




淘宝

package iterator;

import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * 
* @ClassName: TBOrder 
* @Description: 淘宝订单 
* @author minjun
*
 */
public class TBOrder implements Order{
	
	private int size=3;

	private Item[] orders=new Item[size];
	
	private int index=0;
	
	public TBOrder(){
		add("天猫1", 1111, "天猫活动1", 1);
		add("天猫2", 1111, "天猫活动1", 1);
		add("天猫3", 1111, "天猫活动1", 1);
		add("天猫4", 1111, "天猫活动1", 1);
		add("天猫5", 1111, "天猫活动1", 1);
		add("天猫6", 1111, "天猫活动1", 1);
		add("天猫7", 1111, "天猫活动1", 1);
		add("天猫8", 1111, "天猫活动1", 1);
	}
	
	/**添加订单条目*/
	public void add(String name, double price, String desc, int count) {
		
		//如果超过数组大小,就扩容
		if(index>=size-1){
			resize();
		}
			
		orders[index++]=new Item(name, price, desc, count);
	}
	
	/**扩容*/
	private void resize() {
		size=size<<1;//移位运算符--相当于size=size*2
		Item[] newItems=new Item[size];
		//将原始数组内容拷贝到新数组中去
		for(int i=0;i<orders.length;i++){
			newItems[i]=orders[i];
		}
		orders=newItems;
	}

	@Override
	public Iterator<Item> iterator() {
		return new MyIterator();
	}
	
	private class MyIterator implements Iterator<Item>{
		
		private int curr=0;

		@Override
		public boolean hasNext() {
			return orders[curr]!=null;
		}

		@Override
		public Item next() {
			if(hasNext()){
				return orders[curr++];
			}else{
				throw new NoSuchElementException("没有这个元素");
			}
		}

		@Override
		public void remove() {
			throw new UnsupportedOperationException("目前不支持删除操作");
		}
		
	}

}



这样,我就做到了提供一个标准的可以迭代的Order订单接口,然后以两种不同的迭代实现方案(京东、淘宝),为我们的测试类提供了一个可以屏蔽掉内部不同容器的具体实现区别。同时,这也是迭代器模式的运用。

总结:需求--不同容器不同迭代方案,改进--利用相同迭代方案来处理,将不同实现细节分别隐藏到容器自己的实现中。采用的方案就是实现Iterable接口,以及里面的Iterator方法,然后实现自己的迭代方式。








© 著作权归作者所有

上一篇: 责任链模式
下一篇: TCP/IP详解(2)
loda0128
粉丝 93
博文 96
码字总数 119400
作品 0
朝阳
程序员
私信 提问
设计模式之迭代器模式(行为型)

[TOC] 一、模式定义 迭代器模式(Iterator Pattern):提供一种方法来访问聚合对象,而不用暴露这个对象的内部表示,其别名为游标(Cursor),所以迭代器模式是一种对象行为型。 二、模式角色 It...

smileNicky
04/13
0
0
设计模式-迭代器模式

迭代器模式概述 迭代器模式, 我觉得这个图还是很贴切的. 迭代器相当于是电视机的遥控器, 聚合对象相当于是电视机. 电视机中有很多电视频道的集合, 那些电视频道到底是怎么组合在一起的, 我们...

hell03W
2016/11/15
33
0
行为型模式之九:迭代器模式

迭代器模式用于迭代集合对象,他是一个很常用的模式,你可以在之前使用过他,可能你见过像hasNext()和next(),他可能是迭代器模式,比如,你可能迭代访问数据库记录。 迭代器模式类图 迭代器...

刀狂剑痴
2015/08/27
16
0
Javascript设计模式与开发实践详解(四:迭代器模式)

迭代器模式是指一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,不需要关心对象的内部...

littl_Prince
2016/04/08
0
0
迭代器模式(Iterator)

1 场景问题 1.1 工资表数据的整合 考虑这样一个实际应用:整合工资表数据。 这个项目的背景是这样的,项目的客户方收购了一家小公司,这家小公司有自己的工资系统,现在需要整合到客户方已有...

ciyo_yang
2017/07/24
0
0

没有更多内容

加载失败,请刷新页面

加载更多

哪些情况下适合使用云服务器?

我们一直在说云服务器价格适中,具备弹性扩展机制,适合部署中小规模的网站或应用。那么云服务器到底适用于哪些情况呢?如果您需要经常原始计算能力,那么使用独立服务器就能满足需求,因为他...

云漫网络Ruan
今天
10
0
Java 中的 String 有没有长度限制

转载: https://juejin.im/post/5d53653f5188257315539f9a String是Java中很重要的一个数据类型,除了基本数据类型以外,String是被使用的最广泛的了,但是,关于String,其实还是有很多东西...

低至一折起
今天
23
0
OpenStack 简介和几种安装方式总结

OpenStack :是一个由NASA和Rackspace合作研发并发起的,以Apache许可证授权的自由软件和开放源代码项目。项目目标是提供实施简单、可大规模扩展、丰富、标准统一的云计算管理平台。OpenSta...

小海bug
昨天
11
0
DDD(五)

1、引言 之前学习了解了DDD中实体这一概念,那么接下来需要了解的就是值对象、唯一标识。值对象,值就是数字1、2、3,字符串“1”,“2”,“3”,值时对象的特征,对象是一个事物的具体描述...

MrYuZixian
昨天
9
0
解决Mac下VSCode打开zsh乱码

1.乱码问题 iTerm2终端使用Zsh,并且配置Zsh主题,该主题主题需要安装字体来支持箭头效果,在iTerm2中设置这个字体,但是VSCode里这个箭头还是显示乱码。 iTerm2展示如下: VSCode展示如下: 2...

HelloDeveloper
昨天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部