设计模式——迭代器模式
2019-11-05 本文已影响0人
程序员will
什么是迭代器模式
用迭代器来封装集合对象的遍历细节,使调用者能够通过统一的接口来实现对集合的遍历。
迭代器也给集合对象提供了一定的保护,想要遍历集合,直接调用迭代器的方法就好了,我们不知道也不必知道集合内部的数据管理方式。
举个例子
有这样的一个需求。一家集团公司在北京和上海分别有一家子公司,每家公司内部有自己的部门,且自己提供了打印部门的方法。其中一个子公司以数组来保存部门列表,另外一个以ArrayList来保存。现在需要打印所有的部门。
原始实现
部门对象:
//部门对象
public class Dept {
private String name;
public Dept(String name){
this.name= name;
}
public String getName(){
return this.name;
}
}
//北京分公司
public class BJBranch {
ArrayList<Dept> depts;
public BJBranch(){
depts = new ArrayList<Dept>();
//添加部门
depts.add(new Dept("北京-财务部"));
depts.add(new Dept("北京-研发部"));
depts.add(new Dept("北京-开发部"));
}
public ArrayList<Dept> getDepts(){
return depts;
}
}
//上海分公司
public class SHBranch {
Dept[] depts;
public SHBranch(){
depts = new Dept[3];
//添加部门
depts[0] = new Dept("上海-财务部");
depts[1] = new Dept("上海-研发部");
depts[2] = new Dept("上海-开发部");
}
public Dept[] getDepts(){
return depts;
}
}
测试代码
public class TestOld {
public static void main(String[] args) {
// TODO Auto-generated method stub
BJBranch BJ = new BJBranch();
ArrayList<Dept> BJDepts = BJ.getDepts();
SHBranch SH = new SHBranch();
Dept[] SHDepts = SH.getDepts();
//遍历两家子公司的所有部门
/** 由于类型不同,需要两次循环 **/
for(int i=0;i<BJDepts.size();i++){
System.out.println(BJDepts.get(i).getName());
}
for(int i=0;i<SHDepts.length;i++){
System.out.println(SHDepts[0].getName());
}
}
}
从上面的代码中可以看出,由于两家子公司的实现方式不一样,造成循环遍历时自能使用对应的方式来遍历,造成相当大的不便。
改造,使用迭代器模式
//迭代器接口
public interface Iterator {
boolean hasNext();
Object next();
}
//北京分公司的部门迭代器
public class BJBranchIterator implements Iterator{
ArrayList<Dept> depts;
int position = 0;
public BJBranchIterator(ArrayList<Dept> depts){
this.depts = depts;
}
@Override
public boolean hasNext() {
if(position>=depts.size() || depts.get(position)==null){
return false;
}else{
return true;
}
}
@Override
public Object next() {
Dept dept = depts.get(position);
position = position + 1;
return dept;
}
}
//改造后的北京分公司
public class BJBranch {
ArrayList<Dept> depts;
public BJBranch(){
depts = new ArrayList<Dept>();
//添加部门
depts.add(new Dept("北京-财务部"));
depts.add(new Dept("北京-研发部"));
depts.add(new Dept("北京-开发部"));
}
/*public ArrayList<Dept> getDepts(){
return depts;
}*/
//改造为返回Iterator对象,而不是ArrayList
public Iterator createrIterator(){
return new BJBranchIterator(depts);
}
}
//上海分公司的部门迭代器
public class SHBranchIterator implements Iterator{
Dept[] depts;
int position = 0;
public SHBranchIterator(Dept[] depts){
this.depts = depts;
}
@Override
public boolean hasNext() {
if(position>=depts.length|| depts[position]==null){
return false;
}else{
return true;
}
}
@Override
public Object next() {
Dept dept = depts[position];
position = position + 1;
return dept;
}
}
//改造后的上海分公司
public class SHBranch {
Dept[] depts;
public SHBranch(){
depts = new Dept[3];
//添加部门
depts[0] = new Dept("上海-财务部");
depts[1] = new Dept("上海-研发部");
depts[2] = new Dept("上海-开发部");
}
/*public Dept[] getDepts(){
return depts;
}*/
//改造为返回Iterator对象,而不是数组
public Iterator createrIterator(){
return new SHBranchIterator(depts);
}
}
//使用迭代器模式后的代码实现
public class TestNew {
public static void main(String[] args) {
Iterator BJ = new BJBranch().createrIterator();
Iterator SH = new SHBranch().createrIterator();
printDeptName(BJ);
printDeptName(SH);
}
private static void printDeptName(Iterator iterator){
while(iterator.hasNext()){
Dept dept = (Dept) iterator.next();
System.out.println(dept.getName());
}
}
}
从改造后的代码中可以看出,使用迭代器模式改造后,成功的屏蔽了北京与上海分公司遍历的差异。
至此,我们就手写了一个简单的迭代器模式。
总结
由于迭代器的方便性与必要性,Java1.5之后就提供了对Iterator
的支持,目前很多集合对象都支持Iterator
,例如Set
, List
, Map
, SortedSet
, SortedMap
, HashSet
, TreeSet
, ArrayList
, LinkedList
, Vector
等等。
唯一不支持迭代器的可能就是数组吧(栈,队列这些特殊的除外)。
Java.util.Iterator接口定义了三个方法(除hasNext
,next
方法外还有remove
方法);
迭代器的隐式调用
很多语言都支持for each(或者 for in)循环,其内部实现就是调用了迭代器完成遍历。当然,只是一个小常识,更重要的是学会迭代器的设计原理,在需要的时候定义自己的迭代器。
扩展
迭代器模式本身比较简单,甚至我们已经不需要去定义自己的迭代器了(API提供提供的迭代器接口几乎可以满足我们的需要了)。
但迭代器与组合模式结合起来,可以做一些不可思议的事情。