Android编程设计模式之迭代器模式详解
作者:蹲街式等待 发布时间:2023-06-07 01:25:42
本文实例讲述了Android编程设计模式之迭代器模式。分享给大家供大家参考,具体如下:
一、介绍
迭代器模式(Iterator Pattern)又称为游标(Cursor)模式,是行为型设计模式之一。迭代器模式算是一个比较古老的设计模式,其源于对容器的访问,比如Java中的List、Map、数组等,我们知道对容器对象的访问必然会涉及遍历算法,我们可以将遍历的方法封装在容器中,或者不提供遍历方法。如果我们将遍历的方法封装到容器中,那么对于容器类来说就承担了过多的功能,容器类不仅要维护自身内部的数据元素而且还要对外提供遍历的接口方法,因为遍历状态的存储问题还不能对同一个容器同时进行多个遍历操作,如果我们不提供遍历方法而让使用者自己去实现,又会让容器的内部细节暴露无遗,正因于此,迭代模式应运而生,在客户访问类与容器体之间插入了一个第三者——迭代器,很好地解决了上面所述的弊端。
二、定义
提供一种方法顺序访问一个容器对象中的各个元素,而又不需要暴露该对象的内部表示。
三、使用场景
遍历一个容器对象。
四、迭代器模式的UML类图
UML类图:
通用模式代码:
迭代器接口:
public interface Iterator<T> {
/**
* 是否还有下一个元素
* @return true表示有,false表示没有
**/
boolean hasNext();
/**
* 返回当前位置的元素并将位置移至下一位
**/
T next();
}
具体迭代器类:
public class ConcreteIterator<T> implements Iterator<T>{
private List<T> list;
private int cursor = 0;
public ConcreteIterator(List<T> list) {
this.list = list;
}
@Override
public boolean hasNext() {
return cursor != list.size();
}
@Override
public T next() {
T obj = null;
if (this.hasNext()) {
obj = this.list.get(cursor++);
}
return obj;
}
}
容器接口:
public interface Aggregation<T> {
/**
* 添加一个元素
**/
void add(T obj);
/**
* 移除一个元素
**/
void remove(T obj);
/**
* 获取容器的迭代器
**/
Iterator<T> iterator();
}
具体容器类:
public class ConcreteAggregation<T> implements Aggregation<T>{
private List<T> list = new ArrayList<>();
@Override
public void add(T obj) {
list.add(obj);
}
@Override
public void remove(T obj) {
list.remove(obj);
}
@Override
public Iterator<T> iterator() {
return new ConcreteIterator<>(list);
}
}
客户类:
public class Client {
public static void main(String args[]) {
Aggregation<String> a = new ConcreteAggregation<>();
a.add("a");
a.add("b");
a.add("c");
Iterator<String> iterator = a.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next());
}
}
}
角色介绍:
Iterator:迭代器接口,迭代器接口负责定义、访问和遍历元素的接口。
ConcreteIterator:具体迭代器类,具体迭代器类的目的主要是实现迭代器接口,并记录遍历的当前位置。
Aggregate:容器接口,容器接口负责提供创建具体迭代器角色的接口。
ConcreteAggregate:具体容器类,具体迭代器角色与该容器相关联。
Client:客户类。
五、简单实现
小民和小辉分别在公司的两个事业部,某天老板安排任务让他们俩统计一下各自部门的员工数据,这很好办嘛,建一个类用数据结构把所有员工数据存进去即可,老板要看的时候给他用for循环实现,还是比较容易的,下面就先为员工创建一个实体类:
员工实体类:
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) {
super();
this.name = name;
this.age = age;
this.sex = sex;
this.position = position;
}
// 简化代码,省略setter和getter方法
@Override
public String toString() {
return "Employee{" + "name='" + name + '\'' + ", age=" + age + ", sex="
+ sex + ", position='" + position + '\'' + "}";
}
}
小民部门:
public class CompanyMin {
private List<Employee> list = new ArrayList<>();
public CompanyMin(){
list.add(new Employee("小民", 26, "男", "程序猿"));
list.add(new Employee("小芸", 22, "女", "测试"));
list.add(new Employee("小方", 18, "女", "测试"));
list.add(new Employee("可儿", 21, "女", "设计"));
list.add(new Employee("朗情", 19, "女", "设计")); //吐槽一下,为什么就小民一个男的,小辉部门全男的。
}
public List<Employee> getEmployees(){
return list;
}
}
小辉部门:
public class CompanyHui {
private Employee[] array = new Employee[3];
public CompanyHui(){
array[0] = new Employee("辉哥", 28, "男", "程序猿");
array[1] = new Employee("小红", 23, "男", "程序猿");
array[2] = new Employee("小辉", 25, "男", "程序猿");
}
public Employee[] getEmployees(){
return array;
}
}
可见小民和小辉的内部实现是两种方式,小民的人员信息容器的内部实质是使用的一个List类存储人员信息,而小辉的实质上使用的是一个数组,如果老板要查看人员信息就必须遍历两个容器:
Boss查看:
public class Boss {
public static void main(String[] args) {
CompanyHui hui = new CompanyHui();
Employee[] huiList = hui.getEmployees();
for(int i = 0; i < huiList.length; i++){
System.out.println(huiList[i]);
}
CompanyMin min = new CompanyMin();
List minList = min.getEmployees();
for(int i = 0; i < minList.size(); i++){
System.out.println(minList.get(i).toString());
}
}
}
结果:
Employee{name='辉哥', age=28, sex=男, position='程序猿'}
Employee{name='小红', age=23, sex=男, position='程序猿'}
Employee{name='小辉', age=25, sex=男, position='程序猿'}
Employee{name='小民', age=26, sex=男, position='程序猿'}
Employee{name='小芸', age=22, sex=女, position='测试'}
Employee{name='小方', age=18, sex=女, position='测试'}
Employee{name='可儿', age=21, sex=女, position='设计'}
Employee{name='朗情', age=19, sex=女, position='设计'}
这样看似也没有问题,但是如果有多个部门,每个部门有各自的实现,那么我们就要在Boss类中增加一遍遍历逻辑,这样Boss类的功能会越来越多,同时暴露了内部细节。那么我们需要定义一个迭代器接口:
public interface Iterator {
/**
* 是否还有下一个元素
*
* @return true表示有,false表示没有
*/
boolean hasNext();
/**
* 返回当前元素,并将位置移至下一位
*/
Object next();
}
小民的迭代器:
public class MinIterator implements Iterator{
private List<Employee> list;
private int position;
public MinIterator(List<Employee> list){
this.list = list;
}
@Override
public boolean hasNext() {
return !(position > list.size() - 1 || list.get(position) == null);
}
@Override
public Object next() {
Employee e = list.get(position);
position++;
return e;
}
}
小辉的迭代器:
public class HuiIterator implements Iterator{
private Employee[] array;
private int position;
public HuiIterator(Employee[] array){
this.array = array;
}
@Override
public boolean hasNext() {
return !(position > array.length - 1 || array[position] == null);
}
@Override
public Object next() {
Employee e = array[position];
position++;
return e;
}
}
定义容器类的接口:
public interface Company {
/**
* 返回一个迭代器对象
*
* @return 迭代器对象
*/
Iterator iterator();
}
修改一下之前的两个容器类:
public class CompanyHui implements Company{
private Employee[] array = new Employee[3];
public CompanyHui(){
array[0] = new Employee("辉哥", 28, "男", "程序猿");
array[1] = new Employee("小红", 23, "男", "程序猿");
array[2] = new Employee("小辉", 25, "男", "程序猿");
}
public Employee[] getEmployees(){
return array;
}
@Override
public Iterator iterator() {
return new HuiIterator(array);
}
}
public class CompanyMin implements Company{
private List<Employee> list = new ArrayList<>();
public CompanyMin(){
list.add(new Employee("小民", 26, "男", "程序猿"));
list.add(new Employee("小芸", 22, "女", "测试"));
list.add(new Employee("小方", 18, "女", "测试"));
list.add(new Employee("可儿", 21, "女", "设计"));
list.add(new Employee("朗情", 19, "女", "设计"));
}
public List<Employee> getEmployees(){
return list;
}
@Override
public Iterator iterator() {
return new MinIterator(list);
}
}
Boss查看:
public class Boss {
public static void main(String[] args) {
CompanyHui hui = new CompanyHui();
check(hui.iterator());
CompanyMin min = new CompanyMin();
check(min.iterator());
}
private static void check(Iterator iterator){
while (iterator.hasNext()) {
System.out.println(iterator.next().toString());
}
}
}
六、Android源码中的迭代器模式
1、Cursor
当我们使用SQLiteDatabase的query方法查询数据库时,会返回一个Cursor游标对象,该游标的实质就是一个具体的迭代器,我们可以使用它来遍历数据库查询所得的结果集。
七、总结
迭代器模式发展至今,几乎所有的高级语言都有相应的内置实现,对于开发者而言,已经极少会自己去实现迭代器了,所以本章内容更多的是了解而非应用。
优点:
符合面向对象设计原则中的单一职责原则。
支持对容器对象的多种遍历。弱化了容器类与遍历算法之间的关系。
缺点:
类文件的增加。
会出现ConcurrentModificationException异常。
遍历过程是一个单向且不可逆的遍历。
希望本文所述对大家Android程序设计有所帮助。
来源:http://blog.csdn.net/wangzhongshun/article/details/78397569
猜你喜欢
- 文件上传概述实现web开发中的文件上传功能,需完成如下二步操作:在web页面中添加上传输入项在servlet中读取上传文件的数据,并保存到本
- 本文实例讲述了C#中的try catch finally用法。分享给大家供大家参考。具体分析如下:try中的程序块是有可能发生错误的程序块,
- 本文实例为大家分享了Android简单使用PopupWindow的的具体代码,供大家参考,具体内容如下思路1.在res下面创建一个menu文
- 本文实例讲述了Java date format时间格式化操作。分享给大家供大家参考,具体如下:import java.util.Date;i
- 函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。函数式接口可以被隐式转换
- 导入redis的jar包<!-- redis --> <dependency>  
- 本文实例讲述了Android编程之DatePicker和TimePicke简单时间监听用法。分享给大家供大家参考,具体如下:DatePick
- 有段时间没有看视频了,昨天晚上抽了点空时间,又看了下鸿洋大神的视频教程,又抽时间写了个学习记录。代码和老师讲的基本一样,网上也有很多相同的博
- JAVA中实现pdf转图片可以通过第三方提供的架包,这里介绍几种常用的,可以根据自身需求选择使用。一、icepdf。有收费版和开源版,几种方
- 在android提供了一种类型:Parcel。被用作封装数据的容器,封装后的数据可以通过Intent或IPC传递。 除了基本类型以外,只有实
- Java内部类一、 含义在Java编程语言里,程序是由类(class)构建而成的。在一个类的内部也可以声明类,我们把这样的类叫做内部类。二、
- 最近有人问我如何实现倒计时的按钮功能,例如发送验证码,我记得有个CountDownTimer,因为好久没用过了,自己就写了一个,代码如下 n
- 前言在网上看到一个不错的简易版正则匹配和替换的工具,现在补充进来,感觉还不错,效果如下(输入验证中文汉字的正则表达式)在线下载文章导读正则表
- 引言最近一个朋友正在找工作,他说在笔试题中遇到Equals和==有什么区别的题,当时跟他说如果是值类型的,它们没有区别,如果是引用类型的有区
- 一、this用类名定义一个变量的时候,定义的应该只是一个引用,外面可以通过这个引用来访问这个类里面的属性和方法,那们类里面是够也应该有一个引
- float是单精度类型,精度是8位有效数字,取值范围是10的-38次方到10的38次方,float占用4个字节的存储空间double是双精度
- 题目我们可以用2×1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2×1的小矩形无重叠地覆盖一个2×n的大矩形,总共有多少种方法?程序核心
- 一、概述参照官方demo,基于agora开发,输入会议号(频道)和显示名称 参会,可设置参会选项。支持用户注册和登录。支持多人参会。二、效果
- 1、人如何解析算术表达式如何解析算术表达式?或者换种说法,遇到某个算术表达式,我们是如何计算的:①、求值 3+4-5这个表达式,我们在看到3
- 配置详情pom.xmldependency> <groupId>com.baomidou<