`
十三月的
  • 浏览: 168808 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

从JDK看设计模式之行为模式:迭代器(深入)

阅读更多

迭代器模式

目录:

  1. 需求
  2. 使用
  3. JDK源码
  4. 深入:为何要单独抽离出一个Iterator接口?

正文:

      容器,在不同语言中都扮演着重要的角色,如Java中的List、Set和Map。迭代器模式是为容器而生的设计模式,是容器遍历的精灵。

  • 第一部分:需求

     1)使用者:针对多种容器,希望所有遍历方法一样,如容器更换代码无需变动

     2)被使用者:不希望暴露内部实现细节,不同类型容器如何实现不需了解

 

  • 第二部分:使用

      迭代器的使用很简单,下面举例

     例子1:ArrayList

       

public static void main(String[] args) {

		Collection<String> collection = new ArrayList<String>();
		collection.add("开源中国");
		collection.add("csdn");
		collection.add("Iteye");
		collection.add("黑马");
		collection.add("虎嗅网");
		collection.add("环球军事");
		// 取得容器的迭代器
		Iterator<String> iterator = collection.iterator();
		// 遍历
		String content = "";
		while (iterator.hasNext()) {
			content = iterator.next();
			if(content == "Iteye"){
				System.out.println("Bingo  Iteye");
				break;
			}
		}
		
	}

       迭代器的使用方式很简单,显示从容器中取得迭代器,之后根据迭代器的两个方法hasNext和next方法遍历。

 

      例子2:更换ArrayList为HashSet

      

public static void main(String[] args) {

		Collection<String> collection = new HashSet<String>();
		collection.add("开源中国");
		collection.add("csdn");
		collection.add("Iteye");
		collection.add("黑马");
		collection.add("虎嗅网");
		collection.add("环球军事");
		// 取得容器的迭代器
		Iterator<String> iterator = collection.iterator();
		// 遍历
		String content = "";
		while (iterator.hasNext()) {
			content = iterator.next();
			if(content == "Iteye"){
				System.out.println("Bingo  Iteye");
				break;
			}
		}
		
	}

       例子2更换的代码很少,只需要把ArrayList更换为HashSet即可。

 

   例子3:更换HashSet为优先队列PriorityQueue

 

public static void main(String[] args) {

		Collection<String> collection = new PriorityQueue<String>();
		collection.add("开源中国");
		collection.add("csdn");
		collection.add("Iteye");
		collection.add("黑马");
		collection.add("虎嗅网");
		collection.add("环球军事");
		// 取得容器的迭代器
		Iterator<String> iterator = collection.iterator();
		// 遍历
		String content = "";
		while (iterator.hasNext()) {
			content = iterator.next();
			if(content == "Iteye"){
				System.out.println("Bingo  Iteye");
				break;
			}
		}
		
	}

     依旧是简单的更换HashSet为PriorityQueue即可。

 

  • 第三部分:JDK源码

        使用上述代码,完全符合需求中的描述

           1:对使用者来讲,容器遍历方法一样,改变容器类型后其他代码不需改变。

           2:对被使用者容器来讲,不会暴露遍历方法实现的细节。

      其实实现很简单,针对不同类型的容器,ArrayList、LinkedList、Vector或者HashSet,他们各自遍历的方法肯定不一样需要在实现类中分别做实现,然后以同一种方式进行遍历。以List为例,无论是ArrayList或者LinkedList(前者是通过数组实现,后者是通过链表实现)均继承自在AbstractList,父类AbstractList中实现了iterator方法。

public Iterator<E> iterator() {
	return new Itr();
    }

 Itr类是一个内部类

    private class Itr implements Iterator<E> {
	
	int cursor = 0;

	int lastRet = -1;

	int expectedModCount = modCount;

	public boolean hasNext() {
            return cursor != size();
	}

	public E next() {
            checkForComodification();
	    try {
		E next = get(cursor);
		lastRet = cursor++;
		return next;
	    } catch (IndexOutOfBoundsException e) {
		checkForComodification();
		throw new NoSuchElementException();
	    }
	}
//其他省略
}

            代码很简单,在hasNext方法中,通过记录当前遍历cursor和容器大小比较,判断是否有下一个;在next方法中,通过get方法取得下一个元素。当然,get方法是根据不同的容器有不同实现,ArrayList是通过数组下标定位,LinkedList是只能从开始通过指向下一个的引用遍历。

  • 第四部分:深入

       其实,总会有这样的疑问,既然不同的容器都要自己实现自己的遍历方法,那为什么不单独把hasNext方法和next方法直接放到容器里,当成是容器的成员方法?干嘛还要抽象出一个Iterator接口呢?

      有人这样说:在一个复杂系统里,接口的定义其实越细越好,有助于扩展、不同部门人合作等。很有道理,只是觉得并不足以说明放在容器里而不抽象出一个接口的必须性。

   个人觉得原因在于:其实对于容器来讲,它还需要支持一个基本功能即多次遍历。如下

public static void main(String[] args) {

		Collection<String> collection = new ArrayList<String>();
		collection.add("开源中国");
		collection.add("csdn");
		collection.add("Iteye");
		collection.add("黑马");
		collection.add("虎嗅网");
		collection.add("环球军事");
		// 取得容器的迭代器
		Iterator<String> iterator = collection.iterator();
		// 遍历
		String content = "";
		while (iterator.hasNext()) {
			content = iterator.next();
			if(content == "Iteye"){
				System.out.println("Bingo  Iteye");
				break;
			}
		}
		//再次遍历
		Iterator<String> iterator2 = collection.iterator();
		while (iterator.hasNext()) {
			content = iterator2.next();
			if(content == "csdn"){
				System.out.println("Bingo  csdn");
				break;
			}
		}
	}

        假设把hasNext方法和next方法当作容器的成员方法,类似在JDK中的实现,在容器里需要维护有一个变量(index)记录当前访问到第几个元素,以便和容器大小相比较,判断是否有下一个元素(hasNext方法),然后同样需要通过这个index访问元素(next方法)。

  •    如果这个index是成员变量,那么该变量属于类的,不会在每次方法执行后自动消亡,第一次查找“iteye”的时候,在第3个元素中找到了它,index = 2 (下标从0 开始),我还需要查找容器是否包含字符串“csdn”,此时再次执行hasNext方法的时候,index此时是从2开始的,而我们需要的是从头开始遍历,显然不合要求
  •    如果这个index放在方法体hasNext内部,每次在执行hasNext的时候确实能做到从0开始,但这样next方法又无法通过index得到该元素,因为index的作用域是hasNext方法。
  • 放在一个类里就是一个很好的解决方案,每次遍历都new一个新的对象,该对象满足index从0开始,同时next方法和hasNext方法共享该变量。

       在Java中每次执行Iterator方法的时候,总是new 一个新的Iterator的实现类,如HashMap中的KeyIterator。这样确保index每次都是从0开始,而且结束方法Iterator执行完毕后,hasNext方法和next方法仍能够共享变量index,因为此时这两个方法是在同一个类中。java是用内部类的方法来定义的,实际上用外围类也可以,只是内部类可以更好的隐藏细节。

 

1
1
分享到:
评论

相关推荐

    jdk中设计模式

    设计模式通常分为三大类:创建型模式(关注对象的创建)、结构型模式(关注对象的组合和结构)以及行为型模式(关注对象之间的交互)。 【JDK中的设计模式】 1. **Singleton(单例模式)**:如`Runtime`和`...

    设计模式实战、jdk源码|simple-demo.zip

    设计模式分为三大类:创建型模式(如单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式)、结构型模式(如适配器模式、装饰器模式、代理模式、桥接模式、组合模式、外观模式、享元模式)和行为型模式(如...

    JDK中有关23个经典设计模式的示例

    这些模式被广泛应用于Java等面向对象语言中,JDK(Java Development Kit)本身就是一个很好的实践场所,因为它包含了大量使用这些设计模式的例子。下面我们将详细探讨JDK中的23个设计模式及其应用。 1. 单例模式...

    迭代器的用法

    迭代器在Java编程中扮演着至关重要的角色,它是一种设计模式,主要用于遍历集合类中的元素,而无需暴露集合的内部实现。迭代器模式的核心思想是解耦客户端代码与集合对象之间的关系,使得代码更加通用,易于维护。...

    [中文]Head-First设计模式.pdf

    18. 行为型模式:如命令、解释器、迭代器、备忘录、观察者、状态、策略、模板方法、访问者模式,它们关注的是对象之间的交互和职责分配。 通过深入学习和理解这些设计模式,开发者可以写出更高质量、更具扩展性的...

    java迭代器模式.rar

    迭代这个名词对于熟悉Java的人来说绝对不陌生。我们常常使用JDK提供的迭代接口进行java collection的遍历: Iterator it = list.iterator(); while(it.hasNext()){ ...而这就是关于迭代器模式应用很好的例子。

    java 23种设计模式的类图

    17. **迭代器模式(Iterator)**:提供一种方法顺序访问聚合对象的元素,而又不暴露其底层表示。 18. **访问者模式(Visitor)**:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变元素类的前提下...

    【JDK1.8源码剖析】外部迭代器Iterator接口

    文章目录Iterator源码剖析(一)简介(二)源码分析 ...外部迭代器的设计背后体现着迭代器设计模式的思想 (二)源码分析 该接口就只有四种方法 // 是否存在未遍历元素 boolean hasNext(); // 返回下一个元素

    java的设计模式 《设计模式-java语言中的应用.pdf》

    《设计模式——Java语言中的应用》这本书深入探讨了如何在Java中有效地运用这些模式。 1. **单例模式**:确保一个类只有一个实例,并提供全局访问点。在Java中,可以通过双重检查锁定(Double-Checked Locking)或...

    详解java迭代器模式

    _java迭代器模式详解_ ...java迭代器模式是一种非常有用的设计模式,可以使得遍历聚合对象变得更加灵活和方便。通过手动实现迭代器,我们可以隐藏聚合对象的实现细节,提供一个统一的接口来遍历聚合对象。

    java设计模式选择题复习

    ### Java设计模式选择题复习知识点详解 #### 工厂系列模式的优缺点 - **优点**: - **解耦**:工厂模式的...这些知识点对于深入理解和掌握设计模式至关重要,有助于提高编码质量、增强代码的可维护性和可扩展性。

    Java 设计模式最佳实践:提供了一系列 Java 设计模式的最佳实践示例,帮助程序员在设计应用程序或系统时解决常见问题

    Java 设计模式是软件工程中的一种重要思想,它总结了在长期的软件开发实践中,针对特定问题反复...通过阅读“Java 设计模式最佳实践”中的示例,你可以深入理解这些模式,并将它们应用到实际项目中,提升软件开发水平。

    最全 java23种设计模式 Debug模式+内存分析

    - **迭代器模式(Iterator)**:提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。 - **访问者模式(Visitor)**:表示一个作用于某对象结构中的各元素的操作。 - **备忘录模式(Memento)...

    Design Patterns设计模式速查手册HandBood系列(By FengGe整理)

    《Design Patterns设计模式速查手册HandBook系列》是由FengGe精心整理的一份关于软件设计模式的重要参考资料。这本书集合了多种经典的设计模式,主要面向Java开发者,旨在提高开发效率和代码质量,使得软件系统更加...

    设计模式java 版本

    设计模式是软件工程中的一种最佳实践,它是在特定上下文中解决常见问题的模板。在Java中,设计模式尤其重要,因为它们有助于创建可维护、可扩展且高效的代码。本资料包含23种经典设计模式的Java实现,这些模式都是...

    Head First设计模式 Java源代码

    这本书不仅适合初学者,也适合有一定经验的开发者深入理解设计模式。Java源代码是书中理论知识的具体实现,通过实际编程加深对设计模式的理解至关重要。 1. **单例模式** (Singleton): 这是一种限制类实例化次数为...

    设计模式面试题 14 道.pdf

    1. 看懂源代码:如果你不懂设计模式去看Jdk、Spring、SpringMVC、IO等等等等的源码,你会很迷茫,你会寸步难行。 2. 看看前辈的代码:你去一个公司难道都是新项目让你接手?很有可能是接盘的,前辈的开发难道不用...

    java设计模式

    行为型设计模式如责任链模式、命令模式、解释器模式、迭代器模式、访问者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式,主要关注对象之间的交互和行为。 Spring框架,作为Java企业...

    《Java设计模式》课后习题及模拟试题答案

    《Java设计模式》是Java开发领域的一本经典教材,由刘伟编写,深入浅出地讲解了23种GOF(GoF, Gamma, Helm, Johnson, Vlissides)设计模式,旨在提升开发者在软件设计中的灵活性和可维护性。课后习题和模拟试题是...

    JAVA设计模式java 各种设计模式

    Java设计模式是软件开发中的重要概念,它是一种在特定情境下解决常见问题...在阅读《JAVA设计模式java 各种设计模式》的.chm文件时,你可以深入学习每个模式的原理、实现方式以及使用场景,进一步提升自己的编程技能。

Global site tag (gtag.js) - Google Analytics