• 设计模式学习笔记(十六)迭代器模式及其在Java 容器中的应用


    迭代器(Iterator)模式,也叫做游标(Cursor)模式。我们知道,在Java 容器中,为了提高容器遍历的方便性,我们利用迭代器把遍历逻辑从不同类型的集合类中抽取出来,从而避免向外部暴露集合容器的内部结构。这就是迭代器模式的

    一、迭代器模式介绍

    迭代器模式也就是提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。它是一种行为型模式,下面就来看看迭代器模式的结构:

    1.1 迭代器模式的结构

    迭代器模式的结构很简单,就是将聚合对象中的遍历行为分离,并抽象成迭代器类来实现:

    image-20220406161104154

    • Aggregate:抽象聚合接口,定义对聚合对象的一些操作和创建迭代器对象的接口
    • Iterator:抽象迭代器接口,定义访问和遍历聚合元素的接口
    • Aggregate1:具体聚合实现,实现抽象聚合接口,返回一个具体迭代器实例对象
    • Iterator1:具体迭代器实现,实现抽象迭代器接口中所定义的方法

    1.2 迭代器模式的实现

    根据上面的类图,可以实现如下代码:

    /**
     * @description: 抽象聚合接口
     * @author: wjw
     * @date: 2022/4/6
     */
    public interface Aggregate {
        /**
         * 增加对象
         * @param obj 对象
         */
        void add(Object obj);
    
        /**
         * 移除对象
         * @param obj 对象
         */
        void remove(Object obj);
    
        /**
         * 调用迭代器
         * @return 迭代器
         */
        Iterator getIterator();
    }
    
    /**
     * @description: 具体迭代器类
     * @author: wjw
     * @date: 2022/4/6
     */
    public class Aggregate1 implements Aggregate{
    
        private List<Object> list = new ArrayList<>();
    
        @Override
        public void add(Object obj) {
            list.add(obj);
        }
    
        @Override
        public void remove(Object obj) {
            list.remove(obj);
        }
    
        @Override
        public Iterator getIterator() {
            return new Iterator1(list);
        }
    }
    /**
     * @description: 抽象迭代器
     * @author: wjw
     * @date: 2022/4/6
     */
    public interface Iterator {
    
        /**
         * 调用第一个对象
         * @return 对象
         */
        Object first();
    
        /**
         * 调用下一个对象
         * @return 对象
         */
        Object next();
    
        /**
         * 迭代器中是否还有下一个对象
         * @return
         */
        boolean hasNext();
    
    }
    
    /**
     * @description: 具体迭代器类
     * @author: wjw
     * @date: 2022/4/6
     */
    public class Iterator1 implements Iterator{
    
        private List<Object> list = null;
        private int index = -1;
    
        public Iterator1(List<Object> list) {
            this.list = list;
        }
    
        @Override
        public Object first() {
            index = 0;
            Object obj = list.get(index);
            return obj;
        }
    
        @Override
        public Object next() {
            Object obj = null;
            if (this.hasNext()) {
                obj = list.get(++index);
            }
            return obj;
        }
    
        @Override
        public boolean hasNext() {
            if (index < list.size() - 1) {
                return true;
            } else {
                return false;
            }
        }
    }
    /**
     * @description: 客户端类
     * @author: wjw
     * @date: 2022/4/6
     */
    public class Client {
        public static void main(String[] args) {
            Aggregate1 aggregate1 = new Aggregate1();
            aggregate1.add("A");
            aggregate1.add("B");
            aggregate1.add("C");
            System.out.println("聚合对象有:");
            Iterator iterator = aggregate1.getIterator();
            while (iterator.hasNext()) {
                Object obj = iterator.next();
                System.out.println(obj.toString());
            }
            Object first = iterator.first();
            System.out.println("第一个聚合对象是:" + first.toString());
        }
    }
    

    客户端测试场结果为:

    聚合对象有:
    A
    B
    C
    第一个聚合对象是:A
    

    二、迭代器模式的应用场景

    2.1 Java 集合容器

    Java 集合容器中的使用就是容器中的迭代器了,以ArrayList为例,ArrayList是继承Collection的:

    image-20220406193326506

    我们发现ArrayList类里面实现迭代器接口的内部类:

    image-20220406192935330

    其中Itr实现IteratorListItr继承Itr并实现ListIteratorListIteratorIterator功能的扩展。所以实际上ArrayList是抽象聚合和抽象迭代器两者的具体实现,可以画出大致结构图如下:

    image-20220406194540279

    举个使用ArrayList的例子:

    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("A");
        list.add("B");
        list.add("C");
        Iterator<String> iterator = list.iterator();
        System.out.println("ArrayList中的聚合对象为:");
        while (iterator.hasNext()) {
            String next = iterator.next();
            System.out.println(next);
        }
    }
    

    输出结果:

    ArrayList中的聚合对象为:
    A
    B
    C
    

    在日常业务的开发中,迭代器模式使用的场景并不多,下面就来看看关于迭代器的实战

    三、迭代器模式实战

    在本案例中模拟迭代遍历输出公司中树形结构的组织结构关系中雇员列表:

    公司案例

    利用迭代器模式实现的结构如下:

    image-20220406200217207

    上面结构是以Java容器中迭代器模式基础构建的,左边是迭代器的定义,右边是实现的迭代器功能。具体代码结构图如下:

    ├─src
    │  ├─main
    │  │  ├─java
    │  │  │  ├─group
    │  │  │  │      Employee.java
    │  │  │  │      GroupStructure.java
    │  │  │  │      Link.java
    │  │  │  │
    │  │  │  └─lang
    │  │  │          Collection.java
    │  │  │          Iterable.java
    │  │  │          Iterator.java
    │  │  │
    │  │  └─resources
    │  └─test
    │      └─java
    │              ApiTest.java
    

    对于lang包下是迭代器实现部分,具体代码如下:

    /**
     * @description: 可迭代接口定义
     * @author: wjw
     * @date: 2022/4/6
     */
    public interface Iterator<E> {
    
        boolean hasNext();
    
        E next();
    }
    /**
     * @description:
     * @author: wjw
     * @date: 2022/4/6
     */
    public interface Iterable<E> {
    
        Iterator<E> iterator();
    }
    /**
     * @description: 集合功能接口
     * @author: wjw
     * @date: 2022/4/6
     */
    public interface Collection<E, L> extends Iterable<E> {
    
        boolean add(E e);
    
        boolean remove(E e);
    
        boolean addLink(String key, L l);
    
        boolean removeLink(String key);
    
        /**
         * 继承Iterable接口的方法
         * @return Iterator
         */
        @Override
        Iterator<E> iterator();
    }
    

    group包下是组织结构以及聚类对象及其实现,具体代码如下所示:

    /**
     * @description: 雇员类
     * @author: wjw
     * @date: 2022/4/6
     */
    public class Employee {
    
        private String uId;
        private String name;
        private String desc;
    
        public Employee(String uId, String name, String desc) {
            this.uId = uId;
            this.name = name;
            this.desc = desc;
        }
    
        public String getuId() {
            return uId;
        }
    
        public void setuId(String uId) {
            this.uId = uId;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getDesc() {
            return desc;
        }
    
        public void setDesc(String desc) {
            this.desc = desc;
        }
    }
    /**
     * @description: 树节点链路
     * @author: wjw
     * @date: 2022/4/6
     */
    public class Link {
    
        private String fromId;
        private String toId;
    
        public Link(String fromId, String toId) {
            this.fromId = fromId;
            this.toId = toId;
        }
    
        public String getFromId() {
            return fromId;
        }
    
        public void setFromId(String fromId) {
            this.fromId = fromId;
        }
    
        public String getToId() {
            return toId;
        }
    
        public void setToId(String toId) {
            this.toId = toId;
        }
    }
    /**
     * @description: 迭代器功能实现
     * @author: wjw
     * @date: 2022/4/6
     */
    public class GroupStructure implements Collection<Employee, Link> {
    
        /**组织ID*/
        private String groupId;
    
        /**组织名称*/
        private String groupName;
    
        /**雇员列表*/
        private Map<String, Employee> employeeMap = new ConcurrentHashMap<>();
    
        /**组织架构关系*/
        private Map<String, List<Link>> linkMap = new ConcurrentHashMap<>();
    
        /**反向关系链*/
        private Map<String, String> invertedMap = new ConcurrentHashMap<>();
    
        public GroupStructure(String groupId, String groupName) {
            this.groupId = groupId;
            this.groupName = groupName;
        }
    
        @Override
        public boolean add(Employee employee) {
            return null != employeeMap.put(employee.getuId(), employee);
        }
    
        @Override
        public boolean remove(Employee employee) {
            return null != employeeMap.remove(employee.getuId());
        }
    
        @Override
        public boolean addLink(String key, Link link) {
            invertedMap.put(link.getToId(), link.getFromId());
            if (linkMap.containsKey(key)) {
                return linkMap.get(key).add(link);
            } else {
                List<Link> links = new LinkedList<>();
                links.add(link);
                linkMap.put(key, links);
                return true;
            }
        }
    
        @Override
        public boolean removeLink(String key) {
            return null != linkMap.remove(key);
        }
    
        @Override
        public Iterator<Employee> iterator() {
            return new Iterator<Employee>() {
    
                HashMap<String, Integer> keyMap = new HashMap<>();
                int totalIdx = 0;
                //雇员ID,From
                private String fromId = groupId;
                //雇员ID,To
                private String toId = groupId;
    
                @Override
                public boolean hasNext() {
                    return totalIdx < employeeMap.size();
                }
    
                @Override
                public Employee next() {
                    List<Link> links = linkMap.get(toId);
                    int cursorIdx = getCursorIdx(toId);
    
                    //同级扫描
                    if (null == links) {
                        cursorIdx = getCursorIdx(fromId);
                        links = linkMap.get(fromId);
                    }
                    //上级节点扫描
                    while (cursorIdx > links.size() - 1) {
                        fromId = invertedMap.get(fromId);
                        cursorIdx = getCursorIdx(fromId);
                        links = linkMap.get(fromId);
                    }
    
                    //获取节点
                    Link link = links.get(cursorIdx);
                    toId = link.getToId();
                    fromId = link.getFromId();
                    totalIdx++;
    
                    //返回最终结果
                    return employeeMap.get(link.getToId());
                }
    
                //给每个层级定义宽度遍历进度
                public int getCursorIdx(String key) {
                    int idx = 0;
                    if (keyMap.containsKey(key)) {
                        idx = keyMap.get(key);
                        keyMap.put(key, ++idx);
                    } else {
                        keyMap.put(key, idx);
                    }
                    return idx;
                }
            };
        }
    }
    

    最后是测试类及其结果:

    /**
     * @description: 单元测试类
     * @author: wjw
     * @date: 2022/4/6
     */
    public class ApiTest {
    
        private Logger logger = LoggerFactory.getLogger(ApiTest.class);
    
        @Test
        public void test_iterator() {
            GroupStructure groupStructure = new GroupStructure("1", "ethan");
            groupStructure.add(new Employee("2", "花花", "二级部门"));
            groupStructure.add(new Employee("3", "豆包", "二级部门"));
            groupStructure.add(new Employee("4", "蹦蹦", "三级部门"));
            groupStructure.add(new Employee("5", "大烧", "三级部门"));
            groupStructure.add(new Employee("6", "虎哥", "四级部门"));
            groupStructure.add(new Employee("7", "玲姐", "四级部门"));
            groupStructure.add(new Employee("8", "秋雅", "四级部门"));
    
            //添加节点链接
            groupStructure.addLink("1", new Link("1", "2"));
            groupStructure.addLink("1", new Link("1", "3"));
    
            groupStructure.addLink("2", new Link("2", "4"));
            groupStructure.addLink("2", new Link("2", "5"));
    
            groupStructure.addLink("5", new Link("5", "6"));
            groupStructure.addLink("5", new Link("5", "7"));
            groupStructure.addLink("5", new Link("5", "8"));
    
            Iterator<Employee> iterator = groupStructure.iterator();
            while (iterator.hasNext()) {
                Employee employee = iterator.next();
                logger.info("{},雇员 Id: {} Name: {}", employee.getDesc(), employee.getuId(), employee.getName());
            }
        }
    }
    
    21:50:11.087 [main] INFO  ApiTest - 二级部门,雇员 Id: 2 Name: 花花
    21:50:11.089 [main] INFO  ApiTest - 三级部门,雇员 Id: 4 Name: 蹦蹦
    21:50:11.089 [main] INFO  ApiTest - 三级部门,雇员 Id: 5 Name: 大烧
    21:50:11.089 [main] INFO  ApiTest - 四级部门,雇员 Id: 6 Name: 虎哥
    21:50:11.089 [main] INFO  ApiTest - 四级部门,雇员 Id: 7 Name: 玲姐
    21:50:11.089 [main] INFO  ApiTest - 四级部门,雇员 Id: 8 Name: 秋雅
    21:50:11.089 [main] INFO  ApiTest - 二级部门,雇员 Id: 3 Name: 豆包
    

    参考资料

    《重学Java设计模式》

    http://c.biancheng.net/view/1395.html

  • 相关阅读:
    使用 richtextbox 输出程序运行信息
    多线程 更新 winform 控件的值,以避免UI线程的卡顿
    多线程 以及 主程序退出时 子线程的销毁
    supersocket 通过配置文件启动服务 总是 初始化失败的 解决办法
    增删改存储过程 框架
    winform DataGridView 通用初始化
    SQLServer存储过程 实例,很多语法可以以后参考
    Winform中 DataGridView控件中的 CheckBox 的值读出来 始终 为 False ,已解决
    winform中 让 程序 自己重启
    字符数组什么时候要加‘’
  • 原文地址:https://www.cnblogs.com/EthanWong/p/16109790.html
Copyright © 2020-2023  润新知