迭代器模式
1.定义:
提供一种方法顺序访问一个容器对象中的各个元素,而又不需要暴露该对象的内部表示。
2.使用场景:
- 遍历一个容器对象时。
3.UML图
4.详解:
迭代器模式(Iterator Pattern)又称游标模式(Cursor Pattern),是一种行为型设计模式。迭代器模式是一种比较常用的设计模式,其源于对容器的访问,如访问Java中的List,Map,Array中的元素等,必然会涉及遍历算法,这个时候,我们可以将遍历方法封装在容器内或不提供遍历方法。如果封装遍历方法在容器中,对于容器类来讲过,则承担了过多的功能,容器类不仅要维护自身内部的数据元素而且还要对外提供遍历接口方法,因为遍历状态的存储问题还不能对同一个容器同时进行多个遍历操作;如果不提供遍历方法,则需要使用者自己实现,这样就暴露了容器的内部细节,因此,迭代器模式是最佳选择。在客户访问类与容器类之间插入一个第三者——迭代器,可以完美解决上述问题。
下面就以Min和Hui两人统计在职人员信息(包括name,age,sex,job)举例,详见代码:
public static class Employee {
private String name;//姓名
private int age;//年龄
private String sex;//性别
private String job;//职务
public Employee(String name, int age, String sex, String job) {
this.name = name;
this.age = age;
this.sex = sex;
this.job = job;
}
@Override
public String toString() {
return "Emplyee{name=" + name + ",age=" + age + ",sex=" + sex + ",job=" + job + "}";
}
}
然后分别是Min和Hui的统计方法,Min把统计信息存于List中,Hui把统计信息存于Array中:
public static class Min {
private List<Employee> list = new ArrayList<>();
private Employee lilei = new Employee("lilei", 18, "male", "job1");
private Employee hanmeimei = new Employee("hanmeimei", 28, "female", "job2");
private Employee lily = new Employee("lily", 24, "female", "job0");
private Employee tantong = new Employee("tantong", 42, "male", "job0");
public Min() {
list.add(lilei);
list.add(hanmeimei);
list.add(lily);
list.add(tantong);
}
public List<Employee> getList() {
return list;
}
}
public static class Hui {
private Employee[] array = new Employee[4];
private Employee green = new Employee("green", 39, "male", "job0");
private Employee lucy = new Employee("lucy", 20, "female", "job1");
private Employee lancy = new Employee("lancy", 16, "female", "job2");
private Employee jacky = new Employee("jacky", 35, "male", "job1");
public Hui() {
array[0] = green;
array[1] = lucy;
array[2] = lancy;
array[3] = jacky;
}
public Employee[] getArray() {
return array;
}
}
最终汇总时由于二人统计方法存于不同容器,因此遍历方法不一致,需各自遍历,如下:
public static void main(String[] args) {
public static void main(String[] args) {
Min min = new Min();
List<Employee> list = min.getList();
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).toString());
}
System.out.println("===================================================");
Hui hui = new Hui();
Employee[] array = hui.getArray();
for (int i = 0; i < array.length; i++) {
System.out.println(array[i].toString());
}
/**
Emplyee{name=lilei,age=18,sex=male,job=job1}
Emplyee{name=hanmeimei,age=28,sex=female,job=job2}
Emplyee{name=lily,age=24,sex=female,job=job0}
Emplyee{name=tantong,age=42,sex=male,job=job0}
===================================================
Emplyee{name=green,age=39,sex=male,job=job0}
Emplyee{name=lucy,age=20,sex=female,job=job1}
Emplyee{name=lancy,age=16,sex=female,job=job2}
Emplyee{name=jacky,age=35,sex=male,job=job1}
*/
下面使用迭代器模式修改上述代码,首先员工信息类不需要改变,然后定义一个遍历容器数据元素的方法,接口如下:
public interface EmployeeIterator<T> {
boolean hasNext();
T next();
}
接着让Min和Hui两个容器类分别实现该接口,让它们对外提供遍历方法next():
public static class MinIterator implements EmployeeIterator<Employee> {
private List<Employee> list;
private int cursor = 0;
public MinIterator(List<Employee> list) {
this.list = list;
}
@Override
public boolean hasNext() {
return !(cursor > list.size() - 1 || list.get(cursor) == null);
}
@Override
public Employee next() {
return list.get(cursor++);
}
}
public static class HuiIterator implements EmployeeIterator<Employee> {
private Employee[] array;
private int cursor = 0;
public HuiIterator(Employee[] array) {
this.array = array;
}
@Override
public boolean hasNext() {
return !(cursor > array.length - 1 || array[cursor] == null);
}
@Override
public Employee next() {
return array[cursor++];
}
}
到这里就关键了,主角迭代器登场!定义一个第三者——迭代器,代码如下,分别让Min和Hui实现该接口对外提供获取迭代器接口方法,代码如下:
public interface Company {
EmployeeIterator iterator();
}
public static class CompanyMin implements Company {
private List<Employee> list = new ArrayList<>();
private Employee lilei = new Employee("lilei", 18, "male", "job1");
private Employee hanmeimei = new Employee("hanmeimei", 28, "female", "job2");
private Employee lily = new Employee("lily", 24, "female", "job0");
private Employee tantong = new Employee("tantong", 42, "male", "job0");
public CompanyMin() {
list.add(lilei);
list.add(hanmeimei);
list.add(lily);
list.add(tantong);
}
@Override
public EmployeeIterator iterator() {
return new MinIterator(list);
}
}
public static class CompanyHui implements Company {
private Employee[] array = new Employee[4];
private Employee green = new Employee("green", 39, "male", "job0");
private Employee lucy = new Employee("lucy", 20, "female", "job1");
private Employee lancy = new Employee("lancy", 16, "female", "job2");
private Employee jacky = new Employee("jacky", 35, "male", "job1");
public CompanyHui() {
array[0] = green;
array[1] = lucy;
array[2] = lancy;
array[3] = jacky;
}
@Override
public EmployeeIterator iterator() {
return new HuiIterator(array);
}
}
最终汇总信息如下:
public static void main(String[] args) {
CompanyMin companyMin = new CompanyMin();
EmployeeIterator minIterator = companyMin.iterator();
showDetail(minIterator);
System.out.println("===================================================");
CompanyHui companyHui = new CompanyHui();
EmployeeIterator huiIterator = companyHui.iterator();
showDetail(huiIterator);
/**
Emplyee{name=lilei,age=18,sex=male,job=job1}
Emplyee{name=hanmeimei,age=28,sex=female,job=job2}
Emplyee{name=lily,age=24,sex=female,job=job0}
Emplyee{name=tantong,age=42,sex=male,job=job0}
===================================================
Emplyee{name=green,age=39,sex=male,job=job0}
Emplyee{name=lucy,age=20,sex=female,job=job1}
Emplyee{name=lancy,age=16,sex=female,job=job2}
Emplyee{name=jacky,age=35,sex=male,job=job1}
*/
}
private static void showDetail(EmployeeIterator iterator) {
while (iterator.hasNext()) {
System.out.println(iterator.next().toString());
}
}
从使用迭代器模式修改后的方案来看,尽管Min、Hui二人统计数据存于不同容器,但是已让这两个不同容器实现共同遍历接口EmployeeIterator,共同对外提供next方法,这样就实现了在即不用容器封装遍历方法,也不暴露容器内部实现细节的情况下,完成了对容器数据元素的遍历。