设计模式——迭代器模式
本篇博文通过学习尚硅谷韩老师《设计模式》所做,在此非常感谢!
概述
基本介绍
- 迭代器模式(
Iterator Pattern
)是常用的设计模式,属于行为型模式; - 如果我们的集合元素是用不同的方式实现的,有数组,还有 Java的集合类,或者还有其他方式,当客户端要遍历这些集合元素的时候就要使用多种遍历方式,而且还会暴露元素的内部结构,可以考虑使用迭代器模式解决;
- 迭代器模式,提供一种遍历集合元素的统一接口,用一致的方法遍历集合元素,不需要知道集合对象的底层表示,即:不暴露其内部的结构;
细节和注意事项
- 提供一个统一的方法遍历对象,客户不用再考虑聚合的类型,使用一种方法就可以遍历对象了;
- 隐藏了聚合的内部结构,客户端要遍历聚合的时候只能取到迭代器,而不会知道聚合的具体组成;
- 提供了一种设计思想,就是一个类应该只有一个引起变化的原因(叫做单一责任原则)。在聚合类中,我们把迭代器分开,就是要把管理对象集合和遍历对象集合的责任分开,这样一来集合改变的话,只影响到聚合对象。而如果遍历方式改变的话,只影响到了迭代器;
- 当要展示一组相似对象,或者遍历一组相同对象时使用, 适合使用迭代器模式;
- 但是每个聚合对象都要一个迭代器,会生成多个迭代器不好管理类;
UML
问题引入
编写程序展示一个学校院系结构:需求是这样,要在一个页面中展示出学校的院系组成,一个学校有多个学院,一个学院有多个系;这里我们作为演示提供2个学院
分析
如果我们采用传统的方式,学校类
的子类为学院类
,学院类
的子类为下辖的专业类
,这样一来,整个系统的结构就变成了树形的结构,继承的层数较高,而且不宜遍历打印;类过于庞大,一个专业就是一个类,而一个学院类下面又有多个专业类,一旦系统规模增大势必造成类爆炸;
但是换种思路学院下的专业类
是同一种类【因此我们可以把专业类
直接在其对应的学院类
内部使用数组的形式处理掉(包括增删改查等业务逻辑),除去原先的继承关系】;学校下的学院类
属于同一种类,我们可以将这些类加入到List
集合,对外部的这些类采用集合的方式进行增删改查等业务,此时对于该系统来说有两种类型的遍历(数组和集合),因此迭代器模式最为合适;
编码实现
UML
首先构建出UML
图,如下:
编码
首先构建表示专业的专业类Department
做为具体迭代器类内的元素,如下:
package edu.hebeu.element;
/**
* 系别类
* @author 13651
*
*/
public class Department {
private String name;
private String desc;
public Department(String name, String desc) {
super();
this.name = name;
this.desc = desc;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
我们本例中的学院类
提供两个,一个是ComputerCollege计算机学院类
,另一个是MaterialCollege材料学院类
,因此我们先创建出这两个类对应的迭代器类
(同时实现Iterator
接口类,让这两个类都能通过迭代器遍历自己下辖的专业类
),如下
package edu.hebeu.iterator;
import java.util.Iterator;
import edu.hebeu.element.Department;
/**
* 计算机学院(ComputerCollege)的 Iterator类
* @author 13651
*
*/
public class ComputerCollegeIterator implements Iterator<Object>{
/**
* 指定要遍历的元素以什么形式存放
*/
private Department[] departments;
private int position;
public ComputerCollegeIterator(Department[] departments) {
this.departments = departments;
}
/**
* 判断是否还有下一个元素
*/
@Override
public boolean hasNext() {
if(position >= departments.length || departments[position] == null) {
return false;
}
return true;
}
/**
* 取出当前下标位置的元素
*/
@Override
public Object next() {
Department department = departments[position];
position += 1;
return department;
}
/**
* 删除元素,空实现
*/
@Override
public void remove() {
}
}
package edu.hebeu.iterator;
import java.util.Iterator;
import java.util.List;
import edu.hebeu.element.Department;
/**
* 材料学院类(MaterialCollege)的 Iterator类
* @author 13651
*
*/
public class MaterialCollegeIterator implements Iterator<Object>{
/**
* 指定要遍历的元素以什么形式存放
*/
private List<Department> departments;
private int index = -1;
public MaterialCollegeIterator(List<Department> departments) {
this.departments = departments;
}
/**
* 判断还有没有下一个元素
*/
@Override
public boolean hasNext() {
if(index >= departments.size() - 1) {
return false;
} else {
index += 1;
return true;
}
}
/**
* 返回指定位置的元素
*/
@Override
public Object next() {
return departments.get(index);
}
/**
* 删除元素,空实现
*/
@Override
public void remove() {
}
}
此时为了削减程序的耦合,我们应该先创建一个学院类的抽象类College
来将学院的共性抽取
package edu.hebeu.aggregate;
import java.util.Iterator;
/**
* 学院的接口
* @author 13651
*
*/
public interface College {
/**
* 获取学院的名字
* @return
*/
String getName();
/**
* 获取学院的描述
* @return
*/
String getDesc();
/**
* 给学院添加系别
* @param name
* @param desc
*/
void addDepartment(String name, String desc);
/**
* 创建并返回该集合类的Iterator
* @return
*/
Iterator<Object> createIterator();
}
接下来通过实现上述的接口创建具体的学院类计算机学院类ComputerCollege
和材料学院类MaterialCollege
并为每个学院添加其下辖的专业,如下:
package edu.hebeu.aggregate;
import java.util.Iterator;
import edu.hebeu.element.Department;
import edu.hebeu.iterator.ComputerCollegeIterator;
/**
* 计算机学院(ComputerCollege)类
* @author 13651
*
*/
public class ComputerCollege implements College {
private Department[] departments; // 保存该类的系别对象
private int num = 0;
public ComputerCollege() {
departments = new Department[10]; // 最大保存10个元素
addDepartment("软件工程", "软件的开发");
addDepartment("计算机科学技术", "偏向硬件方面的计算机学科");
addDepartment("物联网", "万物互联");
addDepartment("电气工程及其自动化", "电气、自动化、...");
}
@Override
public String getName() {
return "计算机学院";
}
@Override
public String getDesc() {
return "计算机相关的领域";
}
@Override
public void addDepartment(String name, String desc) {
departments[num] = new Department(name, desc);
num += 1;
}
/**
* 创建该类的Iterator对象实例
*/
@Override
public Iterator<Object> createIterator() {
return new ComputerCollegeIterator(departments);
}
}
package edu.hebeu.aggregate;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import edu.hebeu.element.Department;
import edu.hebeu.iterator.MaterialCollegeIterator;
/**
* 材料学院(MaterialCollege)类
* @author 13651
*
*/
public class MaterialCollege implements College {
private List<Department> departments;
public MaterialCollege() {
departments = new ArrayList<>();
addDepartment("冶金工程", "金属冶炼");
addDepartment("化工工程", "化工");
addDepartment("应化", "应用化学");
addDepartment("复材工程", "复合材料");
}
@Override
public String getName() {
return "材料学院";
}
@Override
public String getDesc() {
// TODO Auto-generated method stub
return "材料类的学院";
}
@Override
public void addDepartment(String name, String desc) {
departments.add(new Department(name, desc));
}
@Override
public Iterator<Object> createIterator() {
return new MaterialCollegeIterator(departments);
}
}
此时,迭代器模式搭建的项目的主体就完成了
我们为了更好的遍历,抽取出一个OutputInfo类
来专门处理打印所有学院和其下辖专业的逻辑
package edu.hebeu;
import java.util.Iterator;
import java.util.List;
import edu.hebeu.aggregate.College;
import edu.hebeu.element.Department;
public class OutputInfo {
/**
* 学院的集合
*/
private List<College> colleges;
public OutputInfo(List<College> colleges) {
this.colleges = colleges;
}
/**
* 输出全部的学院和其下的全部系别
*/
public void print() {
Iterator<College> collegesIterator = colleges.iterator();
while(collegesIterator.hasNext()) {
College college = collegesIterator.next(); // 获取该学院对象
System.out.println("-------------------学院:" + college.getName() + "-------------------");
System.out.println(" 描述:" + college.getDesc());
// 调用该学院的printDepartment()方法
printDepartment(college.createIterator());
}
}
/**
* 输出系别
* @param iterator
*/
private void printDepartment(Iterator<Object> iterator) {
while(iterator.hasNext()) {
Department department = (Department) iterator.next();
System.out.println("# " + department.getName() + "---" + department.getDesc());
}
}
}
此时,系统整体就完成了,我们编写客户端来进行测试,如下:
package edu.hebeu;
import java.util.ArrayList;
import java.util.List;
import edu.hebeu.aggregate.College;
import edu.hebeu.aggregate.ComputerCollege;
import edu.hebeu.aggregate.MaterialCollege;
public class Client {
public static void main(String[] args) {
// 创建学院的集合对象实例
List<College> colleges = new ArrayList<>();
// 创建学院对象
ComputerCollege computerCollege = new ComputerCollege();
MaterialCollege materialCollege = new MaterialCollege();
// 将学院对象添加入学院集合
colleges.add(computerCollege);
colleges.add(materialCollege);
// 遍历
OutputInfo outputInfo = new OutputInfo(colleges);
outputInfo.print();
}
}