迭代器模式
1. 需求
编写程序展示一个学校院系结构:一个学校中有多个院,一个学院中有多个系
效果图:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200312134543342.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0x6aW5uZXI=,size_16,color_FFFFFF,t_70)
2.解决方案
使用迭代器模式进行遍历,将数据的存储和数据的遍历进行分离
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200312135942595.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0x6aW5uZXI=,size_16,color_FFFFFF,t_70)
3.迭代器模式的简单介绍
- 迭代器模式(Iterator Pattern)属于一种常见的设计模式,属于行为型模式
- 如果我们的集合元素是用不同的方式实现(array or list or …),当客户端遍历这些集合元素的时候就要使用多种遍历方式,而且还会暴露元素的内部细节.因此使用迭代器模式解决
- 该模式提供了一种遍历集合元素的同一接口(Iterator),从高层来看,使用了一致的方式遍历集合元素,同时不会暴露内部细节。
- 迭代器模式的核心: 将遍历数据的方式和存放数据的方式进行分离。
- 迭代器模式中的角色:
-
抽象聚合(Aggregate)角色:定义存储、添加、删除聚合对象以及创建迭代器对象的接口。【JDK提供了该接口】
-
具体聚合(ConcreteAggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例。
-
抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、first()、next() 等方法。
-
具体迭代器(Concretelterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。
4.代码实现
1.uml
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200312135936642.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0x6aW5uZXI=,size_16,color_FFFFFF,t_70)
2.代码一览
//1.提供数据源
package com.liz.GOF23.iterator.college;
//数据元(数据元素)
public class Department {
private String name;
//描述
private String desc;
public String getName() {
return name;
}
public Department(String name, String desc) {
this.name = name;
this.desc = desc;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
//!! 注:抽象迭代器Iterator在系统中已经提供,无需自己手动编写,直接实现接口即可
//具体迭代器,定义了以List形式存储的遍历思路
//此处以List方式存放Department
public class InfoCollegeIterator implements Iterator {
List<Department> departmentList;
int index = -1;//索引
//构造器 => 内部注入Department
public InfoCollegeIterator(List<Department> departmentList){
this.departmentList = departmentList;
}
//判断集合中还有没有下一个元素
@Override
public boolean hasNext() {
if(index >= departmentList.size() - 1){
return false;
}else{
index +=1;//由于起始点是 -1
return true;
}
}
@Override
public Object next() {
return departmentList.get(index);
}
//空实现remove方法
public void remove(){
}
}
//具体迭代器,定义了以数组形式存储的遍历思路
//此处以数组方式存放Department
public class ComputerCollegeIterator implements Iterator {
Department[] departments;
int position = 0;//遍历的位置
//将数据注入迭代器
public ComputerCollegeIterator(Department[]departments){
this.departments = departments;
}
//判断是否还有下一个
@Override
public boolean hasNext() {
if(position >= departments.length || departments[position] == null){
return false;
}else{
return true;
}
}
@Override
public Object next() {
Department department = departments[position];
position+=1;//后移一位
return department;
}
@Override
public void remove() {
//暂时不需要删除方法 默认实现..
}
}
注: 以上代码已经将迭代器实现完毕,接下来实现数据的存储以及将迭代器放入到聚合角色中
//抽象聚合(内部具体实现了对数据的初始化,同时获取迭代器)
public interface College {
public String getName();
//增加系的方法
public void addDepartment(String name,String desc);
//返回一个迭代器,遍历
public Iterator createIterator();
}
//具体聚合1
public class ComputerCollege implements College {
//数据在此处以 数组形式存储
Department[] departments;
int numOfDepartment = 0;//保存当前数组的对象个数
@Override
public String getName() {
return "计算机学院";
}
//init_data
public ComputerCollege(){
departments = new Department[5];
addDepartment("java","java专业");
addDepartment("php","php专业");
addDepartment("c","c专业");
addDepartment("c++","c++专业");
addDepartment("python","python专业");
}
@Override
public void addDepartment(String name, String desc) {
//真正的数据
Department department = new Department(name, desc);
departments[numOfDepartment] = department;
numOfDepartment+=1;
}
//获取一个迭代器对象
@Override
public Iterator createIterator() {
return new ComputerCollegeIterator(departments);
}
}
//具体聚合2
public class InfoCollege implements College {
//数据在此处以列表形式存储
List<Department> departmentList;
public InfoCollege(){
departmentList = new ArrayList<Department>();
addDepartment("信息安全","信息安全专业");
addDepartment("网络安全","网络安全专业");
addDepartment("服务器安全","服务器安全专业");
}
@Override
public String getName() {
return "信息工程学院";
}
@Override
public void addDepartment(String name, String desc) {
Department department = new Department(name,desc);
departmentList.add(department);
}
//获取迭代器对象
@Override
public Iterator createIterator() {
return new InfoCollegeIterator(departmentList);
}
}
注:在具体聚合中,注意createIterator()方法,内部实例化具体的迭代器对象。
此方法将迭代器对象绑定入聚合对象,同时,迭代器对象可以操作聚合对象内部的数据
(设计的过于巧妙了…)
//输出所有的信息(遍历细节)
public class OutPut {
//学院集合
List<College> collegeList;
public OutPut(List<College> collegeList){
this.collegeList = collegeList;
}
//遍历所有的学院,调用printDepartment输出各个学院的系
public void printCollege(){
//从college中取出所有的学院,java中List已经实现了iterator
Iterator<College> iterator = collegeList.iterator();
while(iterator.hasNext()){
//取出一个学院
College c = iterator.next();
//输出学院的名称
System.out.println("学院名称:"+c.getName());
//打印系信息
printDepartment(c.createIterator());//得到对应的迭代器
System.out.println("-------------------------");
}
}
//输出信息(系)
public void printDepartment(Iterator iterator){
while(iterator.hasNext()){
//从list0开始向后遍历
Department d = (Department) iterator.next();
System.out.println("系名称:"+d.getName());
System.out.println("系描述:"+d.getDesc());
}
}
}
//client
public static void main(String[] args) {
//创建学院
List<College> collegeList = new ArrayList<>();
ComputerCollege computerCollege = new ComputerCollege();
InfoCollege infoCollege = new InfoCollege();
//调整注入的数据
collegeList.add(computerCollege);
collegeList.add(infoCollege);
OutPut outPut = new OutPut(collegeList);
outPut.printCollege();
}
}
输出结果:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200312141350971.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0x6aW5uZXI=,size_16,color_FFFFFF,t_70)
注:可以调整client中的注入的数据,从而实现不同形式的遍历
迭代器模式的细节
优点:
- 提供了一个统一的方法遍历对象,客户不需要再考虑聚合的类型,使用一种方法就可以遍历对象了
- 隐藏了聚合的内部结构,客户端要遍历聚合的时候只能取到迭代器,而隐藏了聚合逻辑
- 提供了一种设计思想,一个类只有一个引起变化的原因(单一责任原则),在聚合类中,我们把迭代器分开,就是要把管理对象集合和遍历对象集合的责任进行分开。如果集合改变了,只会影响到对象,如果遍历方式改变了,只会影响迭代器
- 当展示一组相似对象的时候,或者遍历一组相同对象的时候,适合使用迭代器模式
缺点: 每一个聚合对象都需要一个迭代器,导致生成多个迭代器不好管理类。
参考资料: 韩顺平java设计模式