Java 设计模式之迭代器模式(十五)

做人就要沉下心来,踏踏实实地去努力。别人说你几句,听着。骂你几句,忍着。没有人会跟父母似得惯着你。低下头勤勤恳恳去做事才是正道,心高气傲只会使你废在半路上。你很年轻,还没有资本指点江山。一己是人,众人是天;谋事在人,成事在天,你必须不断充实自己。你只有足够强大,才不会被别人践踏。

设计模式学习,近期我会把23中设计模式都写成博客,敬请期待~
—2021/1/19

定义

迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示。

百度百科

什么是迭代器

public interface Iterator<E> {
    
    
    /**
     * Returns {@code true} if the iteration has more elements.
     * (In other words, returns {@code true} if {@link #next} would
     * return an element rather than throwing an exception.)
     *
     * @return {@code true} if the iteration has more elements
     */
    boolean hasNext();
    /**
     * Returns the next element in the iteration.
     *
     * @return the next element in the iteration
     * @throws NoSuchElementException if the iteration has no more elements
     */
    E next();
}

Iterator(迭代器)是一个接口,需要实现两个方法:

  • hasNext():有没有下一个元素
  • next():当前元素

Iterator(迭代器)常用于数据的遍历,通常使用可能是map集合中使用,其实List集合中也可以使用Iterator(迭代器)来遍历数据.

		ArrayList<String> mList = new ArrayList<>();
        mList.add("张三");
        mList.add("李四");
        mList.add("王五");
        Iterator<String> iterator = mList.iterator();
        //判断有没有下一个元素
        while (iterator.hasNext()) {
    
    
            //输出当前元素 
            Log.i("迭代器模式",iterator.next());
        }

Log图(1.1):
在这里插入图片描述

ArrayList迭代器模式源码分析

源码:


    public Iterator<E> iterator() {
    
    
        return new Itr();
    }
  	//Itr为内部类
    private class Itr implements Iterator<E> {
    
    
    
        protected int limit = ArrayList.this.size;
        int cursor;       // 要返回的下一个元素的索引
        int lastRet = -1; // 返回最后一个元素的索引;如果没有,则返回-1
        int expectedModCount = modCount;

        public boolean hasNext() {
    
    
        	//当前下标 < ArrayList集合长度 则返回true 
            return cursor < limit;
        }

		//获取下一个元素
        @SuppressWarnings("unchecked")
        public E next() {
    
    
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            int i = cursor;
            if (i >= limit)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }
    }

ArrayList源码分析图(2.1):
在这里插入图片描述
在这个实现类中,实现了判断有没有下一个元素(hasNext())以及当前元素是什么(next())

next()分析:

ArrayList源码分析图(2.2):
在这里插入图片描述
在next()中获取当前elementData数组的值,然后在进行数组长度判断,也从这里看出,ArrayList底层是数组

项目需求分析

假设在一个学校中,需要遍历当前的年级,以及当前年级对应班级的小组,

组合模式需求是一样的.

区别:

  • 组合模式可以以单个元素遍历
  • 迭代器模式通过迭代器,可以遍历数组以及集合;

遍历出所有的小组以及年级.

UML分析(3.1):
在这里插入图片描述

  • 红框: 年级
  • 篮框: 小组迭代器

类图看起来稍微复杂一些,不要紧,先一步一步来代码实现,代码实现之后,在回头来看这个UML类图就清晰了~

代码实现

Group01terator第一组(假设是以数组方式存放):

public class Group01terator implements Iterator {
    
    

    //元素数组
    Group[] groups;
    //下标
    int index = 0;

    public Group01terator(Group[] groups) {
    
    
        this.groups = groups;
    }

    /**
     * 判断有无下一个元素
     *
     * @return true有下一个
     */
    @Override
    public boolean hasNext() {
    
    
        //当前下标 > 元素长度  || 当前元素为null 说明没有下一个元素
        if (index >= groups.length || groups[index] == null) {
    
    
            return false;
        } else {
    
    
            //若有下一个元素 当前下标++
            return true;
        }
    }

    /**
     *  返回当前元素
     * @return 当前数组对象
     */
    @Override
    public Object next() {
    
    
        return groups[index++];
    }
}

Group02terator第二组(假设是以集合方式存放):

public class Group02terator implements Iterator {
    
    

     //元素数组
    List<Group> list ;
   
    //下标
    int index = 0;

    public Group02terator(List<Group> list) {
    
    
        this.list = list;
    }

    /**
     * 判断有无下一个元素
     *
     * @return true有下一个
     */
    @Override
    public boolean hasNext() {
    
    
        //当前下标 > 元素长度
        if (index > list.size() - 1) {
    
    
            return false;
        } else {
    
    
            //若有下一个元素 当前下标++
            return true;
        }
    }
    
    /**
     *  返回当前元素
     * @return 当前数组对象
     */
    @Override
    public Object next() {
    
    
        return list.get(index++);
    }
}

Classes 班级接口:

public interface Classes {
    
    
    /**
     * @return 当前具体班级
     */
    public String showClasses();


    /**
     * @param name 具体小组
     */
    public void printGroup(String name);

    /**
     * @return 当前迭代器
     */
    public Iterator createIterator();
}

Classes01一年级:

public class Classes01 implements Classes {
    
    
    Group[] group;
    /**
     * 数组下标
     */
    int index = 0;

    public Classes01() {
    
    
        group= new Group[5];
        printGroup("雄鹰组");
        printGroup("卧龙组");
        printGroup("凤雏组");
        printGroup("神龟组");
    }

    @Override
    public String showClasses() {
    
    
        return "一年级";
    }

    /**
     * @param name 学生姓名
     */
    @Override
    public void printGroup(String name) {
    
    
        group[index++] = new Group(name);
    }

    @Override
    public Iterator createIterator() {
    
    
        return new Group01terator(group);
    }
}

Classes01重写方法介绍:

  • showClasses(): 输出当前的班级
  • printGroup(): 输出当前的小组 (在有参构造中初始化了4个)
  • createIterator(group[]):将初始化的参数,传递给刚刚写好的Group01terator让他迭代,从而实现数据遍历

Classes02二年级:

public class Classes02 implements Classes {
    
    

   List<Group> mlist  =  new ArrayList<Group>();
    /**
     * 数组下标
     */
    int index = 0;

    public Classes02() {
    
    
        printGroup("干饭人组");
        printGroup("Giao组");
        printGroup("神枪手组");
        printGroup("重案八组");
    }

    @Override
    public String showClasses() {
    
    
        return "二年级";
    }

    /**
     * @param name 学生姓名
     */
    @Override
    public void printGroup(String name) {
    
    
        mlist.add(new Group(name));
    }

    @Override
    public Iterator createIterator() {
    
    
        return new Group02terator(mlist);
    }
}

Classes02和Classes01重写方法是一样的,就不重复说了!

OutPut输出结果(为了遵守迪米特原则(最少知道原则)):

public class OutPut {
    
    

    List<Classes> mlist;

    public OutPut(List<Classes> mlist) {
    
    
        this.mlist = mlist;
    }

    public void printClasses() {
    
    
        Iterator<Classes> iterator = mlist.iterator();
        while (iterator.hasNext()) {
    
    
            Classes next = (Classes) iterator.next();
            Log.i("迭代器模式"," ========"+next.showClasses()+" ========");
            printGroup(next.createIterator());
        }
    }

    /**
     * 输出小组
     * @param iterator 当前实现Iterator的类
     */
    public void printGroup(Iterator iterator){
    
    
        while (iterator.hasNext()) {
    
    
            Group next = (Group) iterator.next();
            Log.i("迭代器模式", next.getName());
        }
    }
}

这里只需要在有参构造中传递实现Classes接口的具体实现类,即可完成对所有数据的遍历.

Log(1.2):
在这里插入图片描述

角色分析

  • Iterator:迭代器,用来遍历元素
  • Group01terator / Group02terator 迭代器具体实现
  • Classes:统一的聚合接口,将客户端和具体聚合解耦
  • Classes01 / Classes02:统一聚合接口实现
  • OutPut:分离客户端与具体代码实现,为了遵守迪米特原则(最少知道原则)

总结:

优点:

  • 支持不同对象遍历
  • 在迭代器模式中,增加新的聚合类和迭代器类都很方便,无须修改原有代码
  • 在同一个聚合上可以有多个遍历
  • 不会暴露原有代码实现代码的遍历

缺点:

  • 由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。

完整代码

去设计模式/设计原则主页

原创不易,您的点赞就是对我最大的支持,记得点赞哦~

猜你喜欢

转载自blog.csdn.net/weixin_44819566/article/details/112816640
今日推荐