7.8 迭代器模式 (Iterator pattern)

一. 定义

在实现生活以及程序设计中,经常要访问一个聚合对象中的各个元素,如"数据结构"中的链表遍历,通常的做法是将链表的创建和遍历都放在同一个类中,但这种方法不利于程序的扩展, 如果要更换遍历方法就必须修改程序源码,这违背了开闭原则"",既然遍历方法封装到聚合类中不可取,那聚合类不提供遍历方法,遍历方法由用户自行实现可行吗?答案是同样不可取,因为这种方式会存在两个缺点:

1.暴露了聚合类的内部表示,使其数据不安全;

2.增加了客户端的负担;

迭代器模式能较好的克服以上缺点,它在 客户访问类 与 聚合类之间 插入一个迭代器,这分离了聚合对象与其其遍历行为,对客户也隐藏了内部细节,且满足"单一职责原则" 和 "开闭原则" 如 Java 中的 Collection、List、Set、Map等都包含了迭代器;

迭代器模式在生活中应用的比较广泛,如:物流系统中的传送带,不管传送的是什么物品,都会被打包成一个个箱子.且有一个统一的二维码,这样我们不需要关心箱子里是什么,在分发时只需一个个检查发送的目的地即可.再比如,我们平时乘坐交通工具,都是统一刷卡进站,却不需乘车人信息;

迭代器模式(Iterator pattern)的定义:提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示;

1) 迭代器模式,是常用的设计模式,属于行为模式

2) 如果我们的集合元素是用不同的方式实现的,有数组,还有java集合类当客户端要遍历这些集合元素时,就要使用多种遍历的方式,

    且还会暴露元素的内部结构,这时可考虑使用迭代器模式解决;

3) 迭代器模式,提供一种遍历集合元素的统一接口,用一致的方法遍历集合元素,不需知道集合对象的底层表示(不暴露其内部结构);

二. 特点

1. 优点

1) 提供一个统一的方法遍历对象,客户不用再考虑聚合的类型,使用一种方法就可以遍历对象了;

2) 隐藏了聚合的内部结构,客户端要遍历聚合的时候,只能取得迭代器,而不会知道聚合的具体组成;

3) 提供了一种设计思想,即一个类应该只有一个引发变化的原因(单一职责原则),在聚合类中我们把迭代器分开,就是把管理对象集合

    和 遍历对象集合 的责任分开,这样集合改变的话,只影响到聚合对象,而如果遍历方式改变只影响迭代器;

2. 缺点

每个聚合对象都要一个迭代器, 会生成多个迭代器不好管理类,一定程度上增加了系统的复杂性;

三. 应用场景

当展示一组相似对象,或 遍历一组相同对象时使用迭代器模式;

四. 模式的结构

1.迭代器模式的结构图

7.8 迭代器模式 (Iterator pattern)_第1张图片

2.迭代器模式的角色及职责

1)Aggregate(抽象聚合): 定义存储、添加、删除聚合对象以及创建迭代器对象的接口;

2)ConcreteAggregate(具体聚合): 会持有对象集合,并提供一个方法,返回一个具体迭代器实例,该迭代器可以正确遍历聚合;

3)Iterator(抽象迭代器): 定义访问和遍历聚合元素的接口(系统提供),含有 hasNext. next, remove 等方法;

4)ConcreteIterator(具体的迭代器): 实现抽象迭代器接口方法,完成对聚合对象的遍历,记录遍历的当前位置;

5)IteratorClient(客户端): 通过iterator 和 Aggregate 依赖子类;

五. 模式的实现

编写程序展示一个学校系结构,需求如下:

要在一个页面中展示出学校的院系组成,一个学校有多少个学院,一个学院有多少个系;

--------计算机学院有以下专业-----------

Java工程师 数组

PHP专业

大数据工程师 ==>使用迭代器模式,兼容各种集合

-------信息工程学院有以下专业----------

网络信息安全 集合

电子技术

电子商务

1. 传统方式问题分析

1) 将学院看做是学校的子类,系是学院的子类, 这样实际上是依据组织大小进行分层的;

2) 我们实际要求是:在一个页面展示出学校的院系组成,一个学校有多少学院, 一个学院有多少系

3) 因此传统组织方案不利于遍历的实现;

2. 迭代器模式解决

1) 实例结构图

7.8 迭代器模式 (Iterator pattern)_第2张图片

2) 相关代码实现

object IteratorClient {
    @JvmStatic
    fun main(args: Array) {
        val collegeList = ArrayList()
        val computerCollege = ComputerCollege()
        val infoCollege = InfoCollege()
        collegeList.add(computerCollege)
        collegeList.add(infoCollege)
        //从collageList 取出所有学院, Java中的List 已经实现了Iterator
        val iterator = collegeList.iterator()
        while (iterator.hasNext()) { //遍历所有的学院,然后输出各个学院的各个系
            val college = iterator.next()//取出一个学院
            println(college.getName())
            val collegeIterator = college.createIterator()
            while (collegeIterator.hasNext()) {
                val department: Department = collegeIterator.next() as Department
                println(department.name)
            }
        }
    }
}
//学院接口
interface College {
    fun getName():String //返回学院的名称
    fun addDepartment(name:String,desc:String) //增加系
    fun createIterator():Iterator //返回一个迭代器,遍历
}
//集合中的元素类型--系 Object
data class Department(val name:String, val desc:String)


//计算机学院 
class ComputerCollege : College {
    private var departments = arrayOfNulls(5)
    var numOfDepartment: Int = 0 //保存当前数组的对象个数


    init {
        addDepartment("Java专业", "Java的专业")
        addDepartment("PHP专业", "PHP的专业")
        addDepartment("大数据专业", "大数据专业")
    }


    override fun getName(): String {
        return "===========计算机学院==========="
    }


    override fun addDepartment(name: String, desc: String) {
        val department = Department(name, desc)
        departments[numOfDepartment] = department
        numOfDepartment ++
    }


    override fun createIterator(): Iterator {
        return ComputerCollegeIterator(departments)
    }
}
//信息工程学院
class InfoCollege : College {
    var departments: MutableList = ArrayList()


    override fun getName(): String {
        return "========信息工程学院========="
    }


    init {
        departments = ArrayList()
        addDepartment("网络信息安全","网络信息安全专业")
        addDepartment("电子技术","电子技术专业")
        addDepartment("电子商务","电子商务专业")
    }


    override fun addDepartment(name: String, desc: String) {
        departments.add(Department(name, desc))
    }


    override fun createIterator(): Iterator {
        return InfoCollegeIterator(departments)
    }
}
//迭代器接口
interface Iterator {
    fun hasNext(): Boolean
    fun next():Any?
    fun remove(e:Any?)
}
/**
 * 计算机学院迭代器
 * @param departments 这里我们需要声明计算机学院的Department, 是以Array的方式存放的
 */
class ComputerCollegeIterator(private val departments: Array?) : Iterator {
    var index: Int = 0 //遍历的位置
    //判断list是否还有下一个元素
    override fun hasNext(): Boolean {
        return departments?.let { it[index] } != null && index < departments.size
    }
    //取出下一个元素
    override fun next(): Any? {
        val department = departments?.let { it[index] }
        index+=1
        return department
    }
    override fun remove(e: Any?) {
        TODO("Not yet implemented")
    }
}
/**
 * 信息工程学院迭代器
 * @param departments 这里我们需要声明信息工程学院的Department, 是以List的方式存放的
 */
class InfoCollegeIterator(private val departments:List?) :Iterator {
    var position: Int = 0 //遍历的位置
    //判断是否还有下一个元素
    override fun hasNext(): Boolean {
        return  position < departments?.size!!
    }
    //取出下一个元素
    override fun next(): Any? {
        val department = departments!![position]
        position +=1
        return department
    }
    override fun remove(e: Any?) {
        TODO("Not yet implemented")
    }
}

程序运行结果

===========计算机学院===========
Java专业
PHP专业
大数据专业
===========信息工程学院==========
网络信息安全
电子技术
电子商务

六.迭代器模式在JDK-ArrayList集合应用的源码分析

1.内部类Itr 充当具体实现迭代器Iterator 的类,作为ArrayList内部类;

2.List就是充当了聚合接口,含有一个Iterator() 方法, 返回一个迭代器对象;

3.ArrayList是实现聚合接口List的子类,实现了Iterator()方法

4.Iterator接口由系统提供;

5.迭代器模式解决了 不同集合(ArrayList linkedList) 统一遍历的问题;

7.8 迭代器模式 (Iterator pattern)_第3张图片

你可能感兴趣的:(设计模式,java,设计模式,迭代器模式)