《Android源码设计模式解析与实战》读书笔记(十四)——迭代器模式
来源:互联网 发布:dns优化器 安卓 编辑:程序博客网 时间:2024/05/16 10:22
迭代器模式又称游标(cursor,看到这个单词有没有很熟悉)模式,主要用于对容器的访问,比如 List 、 Map 、数组等,因为访问容器一般会用到遍历算法。如果将遍历方法封装在容器类中,容器类就会承担过多功能,而且由于遍历状态的存储问题,还不能对同一个容器同时进行多个遍历操作,但如果让使用者自己实现遍历方法,又会暴露容器内部实现,因此,迭代器模式应运而生,在客户访问类和容器类之间插入一个第三者——迭代器。
第十四章 解决问题的“第三者”——迭代器模式
1.定义
提供一种方法顺序访问一个容器对象中的各个元素,而又不需要暴露该对象的内部实现。
2.使用场景
1).需要遍历一个容器对象时。
3.简单实现
我们假设一个这样的场景,某一天人事部想统计一下各个部门的人员情况,然后让每个部门自己先将人员信息收集起来。
定义一个员工实体类:
public class Employee { private String name; private int age; private String sex; private String position; public Employee(String name, int age, String sex, String position) { this.name = name; this.age = age; this.sex = sex; this.position = position; } @Override public String toString() { return "Employee{" + "name='" + name + '\'' + ", age=" + age + ", sex='" + sex + '\'' + ", position='" + position + '\'' + '}'; }}
public class TechnicalDepartment { private List<Employee> employeeList = new ArrayList<>(); public TechnicalDepartment() { employeeList.add(new Employee("小赵", 21, "男", "工程师")); employeeList.add(new Employee("小钱", 22, "男", "工程师")); employeeList.add(new Employee("小孙", 23, "男", "工程师")); employeeList.add(new Employee("小李", 24, "男", "项目经理")); } public List<Employee> getEmployeeList() { return employeeList; }}
public class TestingDepartment { private Employee[] employees = new Employee[2]; public TestingDepartment() { employees[0] = new Employee("小周", 25, "女", "测试人员"); employees[1] = new Employee("小吴", 26, "女", "测试人员"); } public Employee[] getEmployees() { return employees; }}
TechnicalDepartment mTechnicalDepartment = new TechnicalDepartment(); for (int i = 0; i < mTechnicalDepartment.getEmployeeList().size(); i++) { System.out.println(mTechnicalDepartment.getEmployeeList().get(i).toString()); } TestingDepartment mTestingDepartment = new TestingDepartment(); for (int i = 0; i < mTestingDepartment.getEmployees().length; i++) { System.out.println(mTestingDepartment.getEmployees()[i]); }
也可以看到每个人员的详细信息,但是问题是,技术部门统计时用的容器是 List ,而测试部门用的是数组,所以人事部门在查看信息的时候,用了两种不同的遍历逻辑。那加入其他部门用的又是另外的容器呢,还得增加不同的遍历逻辑。
所以我们可以增加一个迭代器接口:
public interface Iterator { boolean hasNext(); Employee next();}
然后每个部门都创建一个迭代器来实现遍历:
public class TechnicalDepartmentIterator implements Iterator { private List<Employee> employeeList = new ArrayList<>(); private int index = 0; public TechnicalDepartmentIterator(List<Employee> employeeList) { this.employeeList = employeeList; } @Override public boolean hasNext() { //当下标大于 List 的 size 时,或者当前下标的对象为空,则返回false,停止遍历 return !(index > employeeList.size() - 1 || employeeList.get(index) == null); } @Override public Employee next() { Employee mEmployee = employeeList.get(index); index++; return mEmployee; }}
public class TestingDepartmentIterator implements Iterator { private Employee[] employees = new Employee[2]; private int index = 0; public TestingDepartmentIterator(Employee[] employees) { this.employees = employees; } @Override public boolean hasNext() { //当下标大于 Array 的 length 时,或者当前下标的对象为空,则返回false,停止遍历 return !(index > employees.length - 1 || employees[index] == null); } @Override public Employee next() { Employee mEmployee = employees[index]; index++; return mEmployee; }}
public interface Department { Iterator iterator();}
public class TechnicalDepartment implements Department { private List<Employee> employeeList = new ArrayList<>(); public TechnicalDepartment() { employeeList.add(new Employee("小赵", 21, "男", "工程师")); employeeList.add(new Employee("小钱", 22, "男", "工程师")); employeeList.add(new Employee("小孙", 23, "男", "工程师")); employeeList.add(new Employee("小李", 24, "男", "项目经理")); } @Override public Iterator iterator() { return new TechnicalDepartmentIterator(employeeList); }}
public class TestingDepartment implements Department { private Employee[] employees = new Employee[2]; public TestingDepartment() { employees[0] = new Employee("小周", 25, "女", "测试人员"); employees[1] = new Employee("小吴", 26, "女", "测试人员"); } @Override public Iterator iterator() { return new TestingDepartmentIterator(employees); }}
于是技术部门就可以这样查看了:
TechnicalDepartment mTechnicalDepartment = new TechnicalDepartment(); Iterator mIterator = mTechnicalDepartment.iterator(); while (mIterator.hasNext()) { System.out.println(mIterator.next()); } TestingDepartment mTestingDepartment = new TestingDepartment(); mIterator = mTestingDepartment.iterator(); while (mIterator.hasNext()) { System.out.println(mIterator.next()); }
TechnicalDepartment mTechnicalDepartment = new TechnicalDepartment(); Iterator mIterator = mTechnicalDepartment.iterator(); ergodic(mIterator); TestingDepartment mTestingDepartment = new TestingDepartment(); mIterator = mTestingDepartment.iterator(); ergodic(mIterator);
private void ergodic(Iterator mIterator) { while (mIterator.hasNext()) { System.out.println(mIterator.next()); } }
重新运行可以看到打印输出是一样的。
这样的话,就算增加多少不同的容器都会有相同的遍历逻辑,对于客户端来说也就更简单了。4.总结
迭代器的规定不像其他模式那么严格,实现也因人而异,而且大部分高级语言的容器类都提供了相应的迭代器供开发者使用,而不需要我们自己去实现。拿 Android 来说,除了各种数据体结构(如 List 、 Map 等),自身源码很多也提供了迭代器,比如数据库查询使用的 Cursor ,Cursor 对象其实就是一个迭代器,可以利用它遍历数据库,还有内容提供者的 Cursor 等等。迭代器模式发展至今,几乎每种高级语言都有内置实现,开发者已经很少会自己去实现迭代器了,所以对这个模式也是重在了解原理而非使用。
优点:
1).将多种容器的遍历方式形成统一,弱化了容器类和遍历算法之间的关系。
缺点:
1).类文件的增加。
Demo下载
- 《Android源码设计模式解析与实战》读书笔记(十四)——迭代器模式
- 《Android源码设计模式解析与实战》读书笔记(二十四)——桥接模式
- 《Android源码设计模式解析与实战》读书笔记(十四)
- 《Android源码设计模式解析与实战》读书笔记(二十四)
- 《Android源码设计模式解析与实战》读书笔记(二)——单例模式
- 《Android源码设计模式解析与实战》读书笔记(三)——建造者模式
- 《Android源码设计模式解析与实战》读书笔记(四)——原型模式
- 《Android源码设计模式解析与实战》读书笔记(五)——工厂方法模式
- 《Android源码设计模式解析与实战》读书笔记(七)——策略模式
- 《Android源码设计模式解析与实战》读书笔记(八)——状态模式
- 《Android源码设计模式解析与实战》读书笔记(九)——责任链模式
- 《Android源码设计模式解析与实战》读书笔记(十)——解释器模式
- 《Android源码设计模式解析与实战》读书笔记(十一)——命令模式
- 《Android源码设计模式解析与实战》读书笔记(六)——抽象工厂模式
- 《Android源码设计模式解析与实战》读书笔记(十二)——观察者模式
- 《Android源码设计模式解析与实战》读书笔记(十三)——备忘录模式
- 《Android源码设计模式解析与实战》读书笔记(十五)——模板方法模式
- 《Android源码设计模式解析与实战》读书笔记(十六)——访问者模式
- LRM-00112: multiple values not allowed for parameter 'log'
- QT5串口编写简单的上位机
- Spring-jedis配置
- Keil(MDK-ARM)系列教程(八)_在线调试(Ⅰ)
- 国外程序员整理的机器学习资源大全
- 《Android源码设计模式解析与实战》读书笔记(十四)——迭代器模式
- 接口测试工具postman的环境搭建与使用1
- [李景山php] syn flood 攻击防御方案
- Neutron总结-openvswitch+vxlan网络
- HDU 4864 Task(贪心) (机器完成目标任务, 两个权值, 小范围打表)
- string::size_type和string::size_t和unsigned
- Yocto工具链下制作mkfs.ext4命令
- Java中StringBuffer与StringBuilder的区别
- 面包屑 分页 警告框 面板 模态框 轮播图