迭代器模式

今天来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方法,然后实现自己的迭代方式。








转载于:https://my.oschina.net/u/1378920/blog/408986

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
内容简介: 设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。 本课程内容定位学习设计原则,学习设计模式的基础。在实际开发过程中,并不是一定要求所有代码都遵循设计原则,我们要考虑人力、时间、成本、质量,不是刻意追求完美,要在适当的场景遵循设计原则,体现的是一种平衡取舍,帮助我们设计出更加优雅的代码结构。本章将详细介绍开闭原则(OCP)、依赖倒置原则(DIP)、单一职责原则(SRP)、接口隔离原则(ISP)、迪米特法则(LoD)、里氏替换原则(LSP)、合成复用原则(CARP)的具体内容。 为什么需要学习这门课程? 你在日常的开发中,会不会也遇到过同样的问题。系统出现问题,不知道问题究竟出在什么位置;当遇到产品需求,总是对代码缝缝补补,不能很快的去解决。而且平时工作中,总喜欢把代码堆在一起,出现问题时,不知道如何下手,工作效率很低,而且自己的能力也得不到提升。而这些都源于一个问题,那就是软件设计没做好。这门课能帮助你很好的认识设计模式,让你的能力得到提升。课程大纲: 为了让大家快速系统了解设计模式知识全貌,我为您总结了思维导图,帮您梳理学习重点,建议收藏!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值